Moved thunking functions off to kernel32.dll.
[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 <string.h>
9
10 #include "winerror.h"
11 #include "winbase.h"
12 #include "winnt.h"
13 #include "winreg.h"
14 #include "dplay.h"
15 #include "heap.h"
16 #include "debugtools.h"
17
18 #include "dpinit.h"
19 #include "dplayx_global.h"
20 #include "name_server.h"
21 #include "dplayx_queue.h"
22
23 DEFAULT_DEBUG_CHANNEL(dplay)
24
25
26 /* FIXME: This stuff shouldn't really be here. It indicates a poor architectural coupling */
27 #include "dplobby.h"
28 extern HRESULT DPL_CreateCompoundAddress ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
29                                            LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
30
31
32 /*****************************************************************************
33  * Predeclare the interface implementation structures
34  */
35 typedef struct IDirectPlay2Impl IDirectPlay2AImpl;
36 typedef struct IDirectPlay2Impl IDirectPlay2Impl;
37 typedef struct IDirectPlay3Impl IDirectPlay3AImpl;
38 typedef struct IDirectPlay3Impl IDirectPlay3Impl;
39 typedef struct IDirectPlay4Impl IDirectPlay4AImpl;
40 typedef struct IDirectPlay4Impl IDirectPlay4Impl;
41
42 /*****************************************************************************
43  * IDirectPlay implementation structure
44  *
45  * The philosophy behind this extra pointer dereference is that I wanted to
46  * have the same structure for all types of objects without having to do
47  * alot of casting. I also only wanted to implement an interface in the
48  * object it was "released" with IUnknown interface being implemented in the 1 version.
49  * Of course, with these new interfaces comes the data required to keep the state required
50  * by these interfaces. So, basically, the pointers contain the data associated with
51  * a release. If you use the data associated with release 3 in a release 2 object, you'll
52  * get a run time trap, as that won't have any data.
53  * 
54  */
55 typedef struct tagDirectPlayIUnknownData
56 {
57   DWORD             ref;
58   CRITICAL_SECTION  DP_lock;
59 } DirectPlayIUnknownData;
60
61 typedef struct tagEnumSessionAsyncCallbackData
62 {
63   LPDPENUMSESSIONSCALLBACK2 cb;
64   LPVOID lpContext;
65   DWORD dwTimeout;
66 } EnumSessionAsyncCallbackData;
67
68
69 struct PlayerData
70 {
71   /* Individual player information */
72   DPID dpid;
73   
74   DPNAME name;
75   HANDLE hEvent;
76   LPVOID lpData;
77   DWORD  dwDataSize;
78 };
79 typedef struct PlayerData* lpPlayerData;
80
81 struct PlayerList
82 {
83   DPQ_ENTRY(PlayerList) players;
84
85   lpPlayerData lpPData;
86 };
87 typedef struct PlayerList* lpPlayerList;
88
89 struct GroupData
90 {
91   /* Internal information */
92   struct GroupData* parent; /* If parent == NULL it's a top level group */
93
94   DPQ_HEAD(GroupList)  groups;  /* A group has [0..n] groups */
95   DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */
96
97   DPID idGroupOwner; /* ID of player who owns the group */
98
99   /* Individual group information exposed to outside */
100   DPID   dpid;
101   DPNAME name;
102   LPVOID lpData;
103   DWORD  dwDataSize;
104 };
105 typedef struct GroupData* lpGroupData;
106
107 struct GroupList
108 {
109   DPQ_ENTRY(GroupList) groups;
110
111   lpGroupData lpGData;
112 };
113 typedef struct GroupList* lpGroupList;
114
115 /* Contains all dp1 and dp2 data members */
116 typedef struct tagDirectPlay2Data
117 {
118   BOOL   bConnectionOpen;
119
120   HANDLE hEnumSessionThread;
121
122   EnumSessionAsyncCallbackData enumSessionAsyncCallbackData;
123
124   LPVOID lpNameServerData; /* DPlay interface doesn't know contents */
125
126   BOOL bHostInterface; /* Did this interface create the session */
127
128   DPQ_HEAD(PlayerList) players; /* All players w/ interface */
129   DPQ_HEAD(GroupList)  groups;  /* All main groups w/ interface */
130 } DirectPlay2Data;
131
132 typedef struct tagDirectPlay3Data
133 {
134   BOOL bConnectionInitialized;
135 } DirectPlay3Data;
136
137 typedef struct tagDirectPlay4Data
138 {
139   BOOL dummy;
140 } DirectPlay4Data;
141
142 #define DP_IMPL_FIELDS \
143   DirectPlayIUnknownData*  unk; \
144   DirectPlay2Data*         dp2; \
145   DirectPlay3Data*         dp3; \
146   DirectPlay4Data*         dp4;
147
148 struct IDirectPlay2Impl
149 {
150   ICOM_VFIELD(IDirectPlay2); 
151   DP_IMPL_FIELDS
152 };
153
154 struct IDirectPlay3Impl
155 {
156   ICOM_VFIELD(IDirectPlay3);
157   DP_IMPL_FIELDS
158 };
159
160 struct IDirectPlay4Impl
161 {
162   ICOM_VFIELD(IDirectPlay4);
163   DP_IMPL_FIELDS
164 };
165
166 /* Forward declarations of virtual tables */
167 static ICOM_VTABLE(IDirectPlay2) directPlay2AVT;
168 static ICOM_VTABLE(IDirectPlay3) directPlay3AVT;
169 static ICOM_VTABLE(IDirectPlay4) directPlay4AVT;
170
171 static ICOM_VTABLE(IDirectPlay2) directPlay2WVT;
172 static ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
173 static ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
174
175 /* Local function prototypes */
176 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
177 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid, 
178                                      LPDPNAME lpName, HANDLE hEvent, 
179                                      BOOL bAnsi );
180 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
181 static void DP_SetPlayerData( lpPlayerData lpPData, LPVOID lpData, 
182                               DWORD dwDataSize );
183
184 static lpGroupList DP_FindTopGroup( IDirectPlay2AImpl* This, DPID dpid );
185 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
186                                    LPDPNAME lpName, lpGroupData lpParentData,
187                                    BOOL bAnsi );
188 static void DP_SetGroupData( lpGroupData lpGData, LPVOID lpData,
189                              DWORD dwDataSize );
190 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
191 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
192 static BOOL cbDeletePlayerFromAllGroups( DPID dpId, DWORD dwPlayerType, 
193                                          LPCDPNAME lpName, DWORD dwFlags, 
194                                          LPVOID lpContext );
195 static lpGroupList DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
196 static BOOL cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType, 
197                                    LPCDPNAME lpName, DWORD dwFlags, 
198                                    LPVOID lpContext );
199 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
200
201 /* Helper methods for player/group interfaces */
202 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
203           ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi );
204 static HRESULT WINAPI DP_IF_CreatePlayer
205           ( IDirectPlay2Impl* This, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
206             HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, 
207             DWORD dwFlags, BOOL bAnsi );
208 static HRESULT WINAPI DP_IF_DestroyGroup
209           ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi );
210 static HRESULT WINAPI DP_IF_DestroyPlayer
211           ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi );
212 static HRESULT WINAPI DP_IF_EnumGroupPlayers
213           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, 
214             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
215             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
216 static HRESULT WINAPI DP_IF_EnumGroups
217           ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
218             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
219             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
220 static HRESULT WINAPI DP_IF_EnumPlayers
221           ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
222             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
223             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
224 static HRESULT WINAPI DP_IF_GetGroupData
225           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
226             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
227 static HRESULT WINAPI DP_IF_GetGroupName
228           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
229             LPDWORD lpdwDataSize, BOOL bAnsi );
230 static HRESULT WINAPI DP_IF_GetPlayerData
231           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
232             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
233 static HRESULT WINAPI DP_IF_GetPlayerName
234           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
235             LPDWORD lpdwDataSize, BOOL bAnsi );
236 static HRESULT WINAPI DP_IF_SetGroupName
237           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, 
238             DWORD dwFlags, BOOL bAnsi );
239 static HRESULT WINAPI DP_IF_SetPlayerData
240           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
241             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
242 static HRESULT WINAPI DP_IF_SetPlayerName
243           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, 
244             DWORD dwFlags, BOOL bAnsi );
245 static HRESULT WINAPI DP_IF_AddGroupToGroup
246           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
247 static HRESULT WINAPI DP_IF_CreateGroupInGroup
248           ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup,
249             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
250             DWORD dwFlags );
251 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
252           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
253
254
255 static HRESULT WINAPI DP_SecureOpen
256           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
257             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials );
258
259
260
261
262
263 static DWORD kludgePlayerGroupId = 1000;
264
265 /* ------------------------------------------------------------------ */
266
267
268 BOOL DP_CreateIUnknown( LPVOID lpDP )
269 {
270   ICOM_THIS(IDirectPlay2AImpl,lpDP);
271
272   This->unk = (DirectPlayIUnknownData*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
273                                                   sizeof( *(This->unk) ) );
274   if ( This->unk == NULL )
275   {
276     return FALSE;
277   }
278
279   InitializeCriticalSection( &This->unk->DP_lock );
280
281   IDirectPlay_AddRef( (LPDIRECTPLAY2A)lpDP );
282
283   return TRUE;
284 }
285
286 BOOL DP_DestroyIUnknown( LPVOID lpDP )
287 {
288   ICOM_THIS(IDirectPlay2AImpl,lpDP);
289
290   DeleteCriticalSection( &This->unk->DP_lock );
291   HeapFree( GetProcessHeap(), 0, This->unk );
292
293   return TRUE;
294 }
295
296 BOOL DP_CreateDirectPlay2( LPVOID lpDP )
297 {
298   ICOM_THIS(IDirectPlay2AImpl,lpDP);
299
300   This->dp2 = (DirectPlay2Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
301                                            sizeof( *(This->dp2) ) );
302   if ( This->dp2 == NULL )
303   {
304     return FALSE;
305   }
306
307   This->dp2->bConnectionOpen = FALSE;
308
309   This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
310
311   This->dp2->enumSessionAsyncCallbackData.cb        = NULL; 
312   This->dp2->enumSessionAsyncCallbackData.lpContext = NULL;
313   This->dp2->enumSessionAsyncCallbackData.dwTimeout = INFINITE;
314
315   This->dp2->bHostInterface = FALSE;
316
317   DPQ_INIT(This->dp2->players);
318   DPQ_INIT(This->dp2->groups);
319
320   if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
321   {
322     return FALSE;
323   }
324
325   return TRUE;
326 }
327
328 BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
329 {
330   ICOM_THIS(IDirectPlay2AImpl,lpDP);
331
332   FIXME( ": memory leak\n" );
333
334   if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
335   {
336     TerminateThread( This->dp2->hEnumSessionThread, 0 );
337     CloseHandle( This->dp2->hEnumSessionThread );
338   }
339
340   /* Delete the player and group lists */
341
342   NS_DeleteSessionCache( This->dp2->lpNameServerData );
343   
344   /* Delete the contents */
345   HeapFree( GetProcessHeap(), 0, This->dp2 );
346
347   return TRUE;
348 }
349
350 BOOL DP_CreateDirectPlay3( LPVOID lpDP )
351 {
352   ICOM_THIS(IDirectPlay3AImpl,lpDP);
353
354   This->dp3 = (DirectPlay3Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
355                                            sizeof( *(This->dp3) ) );
356   if ( This->dp3 == NULL )
357   {
358     return FALSE;
359   }
360
361   This->dp3->bConnectionInitialized = FALSE;
362
363   return TRUE;
364 }
365
366 BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
367 {
368   ICOM_THIS(IDirectPlay3AImpl,lpDP);
369
370   /* Delete the contents */
371   HeapFree( GetProcessHeap(), 0, This->dp3 );
372
373   return TRUE;
374 }
375
376 BOOL DP_CreateDirectPlay4( LPVOID lpDP )
377 {
378   ICOM_THIS(IDirectPlay4AImpl,lpDP);
379
380   This->dp4 = (DirectPlay4Data*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
381                                            sizeof( *(This->dp4) ) );
382   if ( This->dp4 == NULL )
383   {
384     return FALSE;
385   }
386
387   return TRUE;
388 }
389
390 BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
391 {
392   ICOM_THIS(IDirectPlay3AImpl,lpDP);
393
394   /* Delete the contents */
395   HeapFree( GetProcessHeap(), 0, This->dp4 );
396
397   return TRUE;
398 }
399
400
401 /* Get a new interface. To be used by QueryInterface. */ 
402 extern 
403 HRESULT directPlay_QueryInterface 
404          ( REFIID riid, LPVOID* ppvObj )
405 {
406
407   if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
408   {
409     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
410                          sizeof( IDirectPlay2Impl ) );
411
412     if( *ppvObj == NULL )
413     {
414        return DPERR_OUTOFMEMORY;
415     }
416
417     /* new scope for variable declaration */
418     {
419       ICOM_THIS(IDirectPlay2Impl,*ppvObj);
420
421       ICOM_VTBL(This) = &directPlay2WVT;
422
423       if ( DP_CreateIUnknown( (LPVOID)This ) &&
424            DP_CreateDirectPlay2( (LPVOID)This )
425          )
426       {
427         return S_OK;
428       }
429
430     }
431
432     goto error; 
433   } 
434   else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
435   {
436     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
437                          sizeof( IDirectPlay2AImpl ) );
438
439     if( *ppvObj == NULL )
440     {
441        return DPERR_OUTOFMEMORY;
442     }
443
444     /* new scope for variable declaration */
445     {
446       ICOM_THIS(IDirectPlay2AImpl,*ppvObj);
447
448       ICOM_VTBL(This) = &directPlay2AVT;
449
450       if ( DP_CreateIUnknown( (LPVOID)This ) &&
451            DP_CreateDirectPlay2( (LPVOID)This )
452          )
453       {
454         return S_OK;
455       }
456
457     }
458
459     goto error;
460   }
461   else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
462   {
463     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
464                          sizeof( IDirectPlay3Impl ) );
465
466     if( *ppvObj == NULL )
467     {
468        return DPERR_OUTOFMEMORY;
469     }
470
471     /* new scope for variable declaration */
472     {
473       ICOM_THIS(IDirectPlay3Impl,*ppvObj);
474
475       ICOM_VTBL(This) = &directPlay3WVT;
476
477       if ( DP_CreateIUnknown( (LPVOID)This ) &&
478            DP_CreateDirectPlay2( (LPVOID)This ) &&
479            DP_CreateDirectPlay3( (LPVOID)This )
480          )
481       {
482         return S_OK;
483       }
484
485     }
486
487     goto error;
488   }
489   else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
490   {
491     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
492                          sizeof( IDirectPlay3AImpl ) );
493
494     if( *ppvObj == NULL )
495     {
496        return DPERR_OUTOFMEMORY;
497     }
498
499     /* new scope for variable declaration */
500     {
501       ICOM_THIS(IDirectPlay3AImpl,*ppvObj);
502
503       ICOM_VTBL(This) = &directPlay3AVT;
504
505       if ( DP_CreateIUnknown( (LPVOID)This ) &&
506            DP_CreateDirectPlay2( (LPVOID)This ) &&
507            DP_CreateDirectPlay3( (LPVOID)This )
508          )
509       {
510         return S_OK;
511       }
512
513     }
514
515     goto error;
516   }
517   else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
518   {
519     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
520                          sizeof( IDirectPlay4Impl ) );
521
522     if( *ppvObj == NULL )
523     {
524        return DPERR_OUTOFMEMORY;
525     }
526
527     /* new scope for variable declaration */
528     {
529       ICOM_THIS(IDirectPlay4Impl,*ppvObj);
530
531       ICOM_VTBL(This) = &directPlay4WVT;
532
533       if ( DP_CreateIUnknown( (LPVOID)This ) &&
534            DP_CreateDirectPlay2( (LPVOID)This ) &&
535            DP_CreateDirectPlay3( (LPVOID)This ) &&
536            DP_CreateDirectPlay4( (LPVOID)This )
537          )
538       {
539         return S_OK;
540       }
541
542     }
543
544     goto error;
545   }
546   else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
547   {
548     *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
549                          sizeof( IDirectPlay4AImpl ) );
550
551     if( *ppvObj == NULL )
552     {
553        return DPERR_OUTOFMEMORY;
554     }
555
556     /* new scope for variable declaration */
557     {
558       ICOM_THIS(IDirectPlay4AImpl,*ppvObj);
559
560       ICOM_VTBL(This) = &directPlay4AVT;
561
562       if ( DP_CreateIUnknown( (LPVOID)This ) &&
563            DP_CreateDirectPlay2( (LPVOID)This ) &&
564            DP_CreateDirectPlay3( (LPVOID)This ) &&
565            DP_CreateDirectPlay4( (LPVOID)This )
566          )
567       {
568         return S_OK;
569       }
570
571     }
572
573     goto error;
574   }
575
576   /* Unsupported interface */
577   *ppvObj = NULL;
578   return E_NOINTERFACE;
579
580 error:
581
582     DP_DestroyDirectPlay4( *ppvObj );
583     DP_DestroyDirectPlay3( *ppvObj );
584     DP_DestroyDirectPlay2( *ppvObj );
585     DP_DestroyIUnknown( *ppvObj );
586     HeapFree( GetProcessHeap(), 0, *ppvObj );
587
588     *ppvObj = NULL;
589     return DPERR_NOMEMORY;
590
591 }
592
593
594 /* Direct Play methods */
595 static HRESULT WINAPI DirectPlay2W_QueryInterface
596          ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
597 {
598   ICOM_THIS(IDirectPlay2Impl,iface);
599   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
600
601   if( IsEqualGUID( &IID_IUnknown, riid ) ||
602       IsEqualGUID( &IID_IDirectPlay2, riid )
603     )
604   {
605     IDirectPlayX_AddRef( iface );
606     *ppvObj = This;
607     return S_OK;
608   }
609   return directPlay_QueryInterface( riid, ppvObj );
610 }
611
612 static HRESULT WINAPI DirectPlay2A_QueryInterface
613          ( LPDIRECTPLAY2A iface, REFIID riid, LPVOID* ppvObj )
614 {
615   ICOM_THIS(IDirectPlay2Impl,iface);
616   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
617
618   if( IsEqualGUID( &IID_IUnknown, riid ) ||
619       IsEqualGUID( &IID_IDirectPlay2A, riid )
620     )
621   {
622     IDirectPlayX_AddRef( iface );
623     *ppvObj = This;
624     return S_OK;
625   }
626
627   return directPlay_QueryInterface( riid, ppvObj );
628 }
629
630 static HRESULT WINAPI DirectPlay3WImpl_QueryInterface
631          ( LPDIRECTPLAY3 iface, REFIID riid, LPVOID* ppvObj )
632 {
633   ICOM_THIS(IDirectPlay3Impl,iface);
634   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
635
636   if( IsEqualGUID( &IID_IUnknown, riid ) ||
637       IsEqualGUID( &IID_IDirectPlay3, riid )
638     )
639   {
640     IDirectPlayX_AddRef( iface );
641     *ppvObj = This;
642     return S_OK;
643   }
644
645   return directPlay_QueryInterface( riid, ppvObj );
646 }
647
648 static HRESULT WINAPI DirectPlay3AImpl_QueryInterface
649          ( LPDIRECTPLAY3A iface, REFIID riid, LPVOID* ppvObj )
650 {
651   ICOM_THIS(IDirectPlay3Impl,iface);
652   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
653
654   if( IsEqualGUID( &IID_IUnknown, riid ) ||
655       IsEqualGUID( &IID_IDirectPlay3A, riid )
656     )
657   {
658     IDirectPlayX_AddRef( iface );
659     *ppvObj = This;
660     return S_OK;
661   }
662
663   return directPlay_QueryInterface( riid, ppvObj );
664 }
665
666 static HRESULT WINAPI DirectPlay4WImpl_QueryInterface
667          ( LPDIRECTPLAY4 iface, REFIID riid, LPVOID* ppvObj )
668 {
669   ICOM_THIS(IDirectPlay4Impl,iface);
670   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
671
672   if( IsEqualGUID( &IID_IUnknown, riid ) ||
673       IsEqualGUID( &IID_IDirectPlay4, riid )
674     )
675   {
676     IDirectPlayX_AddRef( iface );
677     *ppvObj = This;
678     return S_OK;
679   }
680
681   return directPlay_QueryInterface( riid, ppvObj );
682 }
683
684
685 static HRESULT WINAPI DirectPlay4AImpl_QueryInterface
686          ( LPDIRECTPLAY4A iface, REFIID riid, LPVOID* ppvObj )
687 {
688   ICOM_THIS(IDirectPlay4Impl,iface);
689   TRACE("(%p)->(%p,%p)\n", This, riid, ppvObj );
690
691   if( IsEqualGUID( &IID_IUnknown, riid ) ||
692       IsEqualGUID( &IID_IDirectPlay4A, riid )
693     )
694   {
695     IDirectPlayX_AddRef( iface );
696     *ppvObj = This;
697     return S_OK;
698   }
699
700   return directPlay_QueryInterface( riid, ppvObj );
701 }
702
703
704 /* Shared between all dplay types */
705 static ULONG WINAPI DirectPlay2AImpl_AddRef
706          ( LPDIRECTPLAY3 iface )
707 {
708   ULONG refCount;
709   ICOM_THIS(IDirectPlay3Impl,iface);
710
711   refCount = InterlockedIncrement( &This->unk->ref );
712
713   TRACE("ref count incremented to %lu for %p\n", refCount, This );
714
715   return refCount;
716 }
717
718 static ULONG WINAPI DirectPlay2AImpl_Release
719 ( LPDIRECTPLAY3 iface )
720 {
721   ULONG refCount;
722
723   ICOM_THIS(IDirectPlay3Impl,iface);
724
725   refCount = InterlockedDecrement( &This->unk->ref );
726
727   TRACE("ref count decremented to %lu for %p\n", refCount, This );
728
729   /* Deallocate if this is the last reference to the object */
730   if( refCount == 0 )
731   {
732      DP_DestroyDirectPlay4( This );
733      DP_DestroyDirectPlay3( This );
734      DP_DestroyDirectPlay2( This );
735      DP_DestroyIUnknown( This );
736      HeapFree( GetProcessHeap(), 0, This );
737   }
738
739   return refCount;
740 }
741
742 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
743           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
744 {
745   lpGroupList  lpGList;
746   lpPlayerList lpPList;
747   lpPlayerList lpNewPList;
748
749   ICOM_THIS(IDirectPlay2AImpl,iface);
750
751   TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idGroup, idPlayer );
752
753   /* Find the group */
754   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
755   {
756     return DPERR_INVALIDGROUP;
757   }
758
759   /* Find the player */
760   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
761   {
762     return DPERR_INVALIDPLAYER;
763   }
764
765   /* Create a player list (ie "shortcut" ) */
766   lpNewPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
767                                         sizeof( *lpNewPList ) );
768   if( lpNewPList == NULL ) 
769   {
770     return DPERR_CANTADDPLAYER;
771   }   
772
773   /* Add the shortcut */
774   lpNewPList->lpPData = lpPList->lpPData;
775
776   /* Add the player to the list of players for this group */
777   DPQ_INSERT(lpGList->lpGData->players,lpNewPList,players);
778
779   /* Send a ADDPLAYERTOGROUP message */
780   FIXME( "Not sending message\n" );
781
782   return DP_OK;
783 }
784
785 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
786           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
787 {
788   ICOM_THIS(IDirectPlay2Impl,iface);
789   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idPlayer );
790   return DP_OK;
791 }
792
793
794 static HRESULT WINAPI DirectPlay2AImpl_Close
795           ( LPDIRECTPLAY2A iface )
796 {
797   ICOM_THIS(IDirectPlay2Impl,iface);
798   FIXME("(%p)->(): stub\n", This );
799   return DP_OK;
800 }
801
802 static HRESULT WINAPI DirectPlay2WImpl_Close
803           ( LPDIRECTPLAY2 iface )
804 {
805   ICOM_THIS(IDirectPlay2Impl,iface);
806   FIXME("(%p)->(): stub\n", This );
807   return DP_OK;
808 }
809
810 static
811 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
812                             LPDPNAME lpName, lpGroupData lpParentData,
813                             BOOL bAnsi )
814 {
815   lpGroupList lpGroup;
816
817   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
818
819   /* Allocate the new space and add to end of high level group list */
820   lpGroup = (lpGroupList) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
821                                      sizeof( *lpGroup ) );
822
823   if( lpGroup == NULL )
824   {
825     return NULL;
826   }
827
828   /* Allocate storage for the group and associate it with the list element */
829   lpGroup->lpGData = (lpGroupData) HeapAlloc( GetProcessHeap(),
830                                               HEAP_ZERO_MEMORY,
831                                               sizeof(*(lpGroup->lpGData)) );
832
833   if( lpGroup->lpGData == NULL )
834   {
835     /* FIXME: Memory leak */
836     return NULL;
837   }
838
839   DPQ_INSERT(This->dp2->groups,lpGroup,groups);
840
841   if( *lpid == DPID_UNKNOWN )
842   {
843     /* Assign the next available player ID - FIXME crap solution */
844     lpGroup->lpGData->dpid = kludgePlayerGroupId++;
845   }
846   else
847   {
848     /* Set the desired player ID - no sanity checking to see if it exists */
849     lpGroup->lpGData->dpid = *lpid;
850   }
851
852   DP_CopyDPNAMEStruct( &lpGroup->lpGData->name, lpName, bAnsi );
853  
854   lpGroup->lpGData->parent = lpParentData;
855
856   return lpGroup->lpGData;
857 }
858
859 /* This method assumes that all links to it are already deleted */
860 static void 
861 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
862 {
863   lpGroupList lpGList;
864
865   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
866
867   DPQ_REMOVE_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGList );
868
869   if( lpGList == NULL )
870   {
871     ERR( "DPID 0x%08lx not found\n", dpid );
872     return;
873   }
874
875   /* Delete player */
876   DP_DeleteDPNameStruct( &lpGList->lpGData->name );
877   HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
878
879   /* Remove and Delete Player List object */
880   HeapFree( GetProcessHeap(), 0, lpGList );
881  
882 }
883
884 /* This function only finds top level groups */
885 static lpGroupList DP_FindTopGroup( IDirectPlay2AImpl* This, DPID dpid )
886 {
887   lpGroupList lpGroups;
888
889   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
890
891   /* Does the group exist? */
892   if( ( lpGroups = DP_FindAnyGroup( This, dpid ) ) == NULL )  
893   {
894     return NULL;
895   }
896
897   /* Is this group a top level group? */
898   if( lpGroups->lpGData->parent )
899   {
900     return lpGroups;
901   }
902   else
903   {
904     return NULL;
905   }
906 }
907
908 static lpGroupList DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
909 {
910   lpGroupList lpGroups;
911
912   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
913
914   DPQ_FIND_ENTRY( This->dp2->groups, groups, lpGData->dpid, dpid, lpGroups );
915
916   return lpGroups;
917 }
918
919 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
920           ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
921 {
922   lpGroupData lpGData;
923
924   ICOM_THIS(IDirectPlay2Impl,iface);
925
926   FIXME("(%p)->(%p,%p,%p,0x%08lx,0x%08lx): stub\n", This, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags );
927
928   lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, 
929                             NULL /* Top level group */, TRUE /* Ansi */ );
930
931   if( lpGData == NULL )
932   {
933     return DPERR_CANTADDPLAYER; /* yes player not group */
934   }
935
936   DP_SetGroupData( lpGData, lpData, dwDataSize );
937
938   /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone,
939             local and remote, that belongs to this session. This will not
940             be done by calling SetPlayerData */
941   FIXME( "Should broadcast group creation to everything in session\n" );
942
943   return DP_OK;
944 }
945
946 static void
947 DP_SetGroupData( lpGroupData lpGData, LPVOID lpData, DWORD dwDataSize )
948 {
949   /* Clear out the data with this player */
950   if( lpGData->dwDataSize != 0 )
951   {
952         HeapFree( GetProcessHeap(), 0, lpGData->lpData );
953         lpGData->lpData = NULL;
954         lpGData->dwDataSize = 0;
955   }
956
957   /* Reallocate for new data */
958   if( lpData )
959   {
960     lpGData->lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
961                                  sizeof( dwDataSize ) );
962     memcpy( lpGData->lpData, lpData, dwDataSize );
963     lpGData->dwDataSize = dwDataSize;
964   }
965
966 }
967
968
969 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
970           ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
971 {
972   ICOM_THIS(IDirectPlay2Impl,iface);
973   FIXME("(%p)->(%p,%p,%p,0x%08lx,0x%08lx): stub\n", This, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags );
974   return DP_OK;
975 }
976
977 /* This function will just create the storage for the new player.
978  * In the future it may want to intialize, but for the time being
979  * that will be done seperately. 
980  * 
981  * If *lpid == DPID_UNKNOWN then assign the next available player
982  */
983 static 
984 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid, 
985                               LPDPNAME lpName, HANDLE hEvent, BOOL bAnsi )
986 {
987   lpPlayerList lpPlayer;
988
989   TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
990
991   /* Allocate the new space and add to end of interface player list */
992   lpPlayer = (lpPlayerList) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
993                                        sizeof( *lpPlayer ) );
994
995   if( lpPlayer == NULL )
996   {
997     return NULL;
998   }
999
1000   /* Allocate the storage for the player and associate it with list element */
1001   lpPlayer->lpPData = (lpPlayerData) HeapAlloc( GetProcessHeap(), 
1002                                                 HEAP_ZERO_MEMORY,
1003                                                 sizeof(*(lpPlayer->lpPData)) );
1004   if( lpPlayer->lpPData == NULL )
1005   {
1006     /* FIXME: Memory leak */
1007     return NULL;
1008   }
1009
1010   /* Insert the player list into the master list of players */
1011   DPQ_INSERT( This->dp2->players, lpPlayer, players );
1012
1013   if( *lpid == DPID_UNKNOWN )
1014   {
1015     /* Assign the next available player ID - FIXME crap solution */
1016     lpPlayer->lpPData->dpid = kludgePlayerGroupId++; 
1017   }
1018   else 
1019   {
1020     /* Set the desired player ID - no sanity checking to see if it exists */
1021     lpPlayer->lpPData->dpid = *lpid;
1022   }
1023
1024   DP_CopyDPNAMEStruct( &lpPlayer->lpPData->name, lpName, bAnsi );
1025
1026   lpPlayer->lpPData->hEvent = hEvent;
1027
1028   return lpPlayer->lpPData;
1029 }
1030
1031 /* Delete the contents of the DPNAME struct */
1032 static void
1033 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1034 {
1035   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->psn.lpszShortNameA ); 
1036   HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->pln.lpszLongNameA ); 
1037 }
1038
1039 /* This method assumes that all links to it are already deleted */
1040 static void
1041 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1042 {
1043   lpPlayerList lpPlayers;
1044
1045   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1046
1047   DPQ_REMOVE_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
1048
1049   if( lpPlayers == NULL )
1050   {
1051     ERR( "DPID 0x%08lx not found\n", dpid );
1052     return;
1053   }
1054  
1055   /* Delete player */
1056   DP_DeleteDPNameStruct( &lpPlayers->lpPData->name );
1057   HeapFree( GetProcessHeap(), 0, lpPlayers->lpPData );
1058
1059   /* Delete Player List object */
1060   HeapFree( GetProcessHeap(), 0, lpPlayers );
1061
1062 }
1063
1064 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1065 {
1066   lpPlayerList lpPlayers;
1067
1068   TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1069
1070   DPQ_FIND_ENTRY( This->dp2->players, players, lpPData->dpid, dpid, lpPlayers );
1071
1072   return lpPlayers;
1073 }
1074
1075 /* Basic area for Dst must already be allocated */
1076 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1077 {
1078   if( lpSrc == NULL )
1079   {
1080     ZeroMemory( lpDst, sizeof( *lpDst ) );
1081     lpDst->dwSize = sizeof( *lpDst );
1082     return TRUE;
1083   }
1084
1085   if( lpSrc->dwSize != sizeof( *lpSrc) )   
1086   {
1087     return FALSE;
1088   }
1089
1090   /* Delete any existing pointers */
1091   if( lpDst->psn.lpszShortNameA )
1092   {
1093     HeapFree( GetProcessHeap(), 0, lpDst->psn.lpszShortNameA );
1094   }
1095
1096   if( lpDst->pln.lpszLongNameA )
1097   {
1098     HeapFree( GetProcessHeap(), 0, lpDst->psn.lpszShortNameA );
1099   }
1100
1101   /* Copy as required */
1102   memcpy( lpDst, lpSrc, lpSrc->dwSize ); 
1103
1104   if( bAnsi )
1105   {
1106     if( lpSrc->psn.lpszShortNameA )
1107     {
1108       lpDst->psn.lpszShortNameA = 
1109         HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, 
1110                         lpSrc->psn.lpszShortNameA );
1111     }
1112     if( lpSrc->pln.lpszLongNameA )
1113     {
1114       lpDst->pln.lpszLongNameA =
1115         HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY,
1116                         lpSrc->pln.lpszLongNameA );
1117     }
1118   }
1119   else
1120   {
1121     if( lpSrc->psn.lpszShortNameA )
1122     {
1123       lpDst->psn.lpszShortName = 
1124         HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY,
1125                         lpSrc->psn.lpszShortName );
1126     }
1127     if( lpSrc->pln.lpszLongNameA )
1128     {
1129       lpDst->pln.lpszLongName =
1130         HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY,
1131                         lpSrc->pln.lpszLongName );
1132     }
1133   }
1134
1135   return TRUE;
1136 }
1137
1138 static void 
1139 DP_SetPlayerData( lpPlayerData lpPData, LPVOID lpData, DWORD dwDataSize )
1140 {
1141   /* Clear out the data with this player */
1142   if( lpPData->dwDataSize != 0 )
1143   {
1144         HeapFree( GetProcessHeap(), 0, lpPData->lpData );
1145         lpPData->lpData = NULL;
1146         lpPData->dwDataSize = 0;
1147   }
1148
1149   /* Reallocate for new data */
1150   if( lpData )
1151   {
1152     lpPData->lpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1153                                    sizeof( dwDataSize ) );
1154     memcpy( lpPData->lpData, lpData, dwDataSize );
1155     lpPData->dwDataSize = dwDataSize;
1156   }
1157   
1158 }
1159
1160 static HRESULT WINAPI DP_IF_CreatePlayer 
1161 ( IDirectPlay2Impl* This, 
1162   LPDPID lpidPlayer, 
1163   LPDPNAME lpPlayerName, 
1164   HANDLE hEvent, 
1165   LPVOID lpData, 
1166   DWORD dwDataSize, 
1167   DWORD dwFlags,
1168   BOOL bAnsi )
1169 {
1170   lpPlayerData lpPData;
1171
1172   TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n", 
1173          This, lpidPlayer, lpPlayerName, hEvent, lpData, 
1174          dwDataSize, dwFlags, bAnsi );
1175
1176   if( dwFlags == 0 ) 
1177   {
1178     dwFlags = DPPLAYER_SPECTATOR;
1179   }
1180
1181   /* Verify we know how to handle all the flags */
1182   if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1183          ( dwFlags & DPPLAYER_SPECTATOR )
1184        )
1185     )
1186   {
1187     /* Assume non fatal failure */
1188     ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
1189   }
1190
1191   if ( dwFlags & DPPLAYER_SERVERPLAYER )
1192   {
1193     /* We have a request to create the "master" of the session.
1194      * This computer needs to be the session host and the server
1195      * player can't have been created yet. 
1196      */
1197     if( ( !This->dp2->bHostInterface ) ||
1198         ( DP_FindPlayer( This, DPID_SERVERPLAYER ) )
1199       )
1200     {
1201       TRACE( "Denying SERVERPLAYER creation\n" );
1202       return DPERR_CANTCREATEPLAYER;
1203     }
1204
1205     *lpidPlayer = DPID_SERVERPLAYER;
1206   }
1207   else
1208   {
1209     *lpidPlayer = DPID_UNKNOWN;
1210   }
1211
1212   lpPData = DP_CreatePlayer( This, lpidPlayer, 
1213                              lpPlayerName, hEvent, bAnsi );
1214
1215   if( lpPData == NULL )
1216   {
1217     return DPERR_CANTADDPLAYER;
1218   }
1219
1220   /* Update the information and send it to all players in the session */
1221   DP_SetPlayerData( lpPData, lpData, dwDataSize );  
1222
1223
1224   /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone, 
1225             local and remote, that belongs to this session. This will not 
1226             be done by calling SetPlayerData */
1227   FIXME( "Should broadcast player creation to everything in session\n" );
1228
1229   return DP_OK;
1230 }
1231
1232 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1233           ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1234 {
1235   ICOM_THIS(IDirectPlay2Impl,iface);
1236   return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, 
1237                            lpData, dwDataSize, dwFlags, TRUE );
1238 }
1239
1240 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1241           ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1242 {
1243   ICOM_THIS(IDirectPlay2Impl,iface);
1244   return DP_IF_CreatePlayer( This, lpidPlayer, lpPlayerName, hEvent, 
1245                            lpData, dwDataSize, dwFlags, FALSE );
1246 }
1247
1248 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1249           ( IDirectPlay2Impl* This, DPID idGroup, DPID idPlayer, BOOL bAnsi )
1250 {
1251   lpGroupList  lpGList;
1252   lpPlayerList lpPList;
1253   
1254   TRACE("(%p)->(0x%08lx,0x%08lx,%u)\n", This, idGroup, idPlayer, bAnsi );
1255
1256   /* Find the group */
1257   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1258   {
1259     return DPERR_INVALIDGROUP;
1260   }
1261
1262   /* Find the player */
1263   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1264   {
1265     return DPERR_INVALIDPLAYER;
1266   }
1267
1268   /* Remove the player shortcut from the group */
1269   DPQ_REMOVE_ENTRY( lpGList->lpGData->players, players, lpPData->dpid, idPlayer, lpPList );
1270
1271   if( lpPList == NULL )
1272   {
1273     return FALSE;
1274   }
1275
1276   /* Delete the Player List element */
1277   HeapFree( GetProcessHeap(), 0, lpPList );
1278
1279   /* Need to send a DELETEPLAYERFROMGROUP message */
1280   FIXME( "Need to send a message\n" );
1281
1282   return DP_OK;
1283 }
1284
1285 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1286           ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1287 {
1288   ICOM_THIS(IDirectPlay2Impl,iface);
1289   return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, TRUE );
1290 }
1291
1292 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1293           ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1294 {
1295   ICOM_THIS(IDirectPlay2Impl,iface);
1296   return DP_IF_DeletePlayerFromGroup( This, idGroup, idPlayer, FALSE );
1297 }
1298
1299 typedef struct _DPRGOPContext
1300 {
1301   LPDIRECTPLAY3 iface;
1302   BOOL          bAnsi;
1303   DPID          idGroup;
1304 } DPRGOPContext, *lpDPRGOPContext;
1305
1306 static BOOL 
1307 cbRemoveGroupOrPlayer(
1308     DPID            dpId,
1309     DWORD           dwPlayerType,
1310     LPCDPNAME       lpName,
1311     DWORD           dwFlags,
1312     LPVOID          lpContext )
1313 {
1314   lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1315   TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n", 
1316            dpId, dwPlayerType, lpCtxt->idGroup );
1317
1318   if( dwPlayerType == DPPLAYERTYPE_GROUP )
1319   {
1320     if( FAILED( IDirectPlayX_DeleteGroupFromGroup( lpCtxt->iface, 
1321                                                    lpCtxt->idGroup, dpId ) 
1322               ) 
1323       )
1324     {
1325       ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n", 
1326              dpId, lpCtxt->idGroup );
1327     }
1328   }
1329   else
1330   {
1331     if( FAILED( IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface, 
1332                                                     lpCtxt->idGroup, dpId )
1333               )
1334       )
1335     {
1336       ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
1337              dpId, lpCtxt->idGroup );
1338     }
1339   }
1340   
1341   return TRUE; /* Continue enumeration */
1342 }
1343
1344 static HRESULT WINAPI DP_IF_DestroyGroup
1345           ( IDirectPlay2Impl* This, DPID idGroup, BOOL bAnsi )
1346 {
1347   lpGroupList lpGList;
1348   DPRGOPContext context;
1349
1350   FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idGroup, bAnsi );
1351
1352   /* Find the group */
1353   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1354   {
1355     return DPERR_INVALIDPLAYER; /* yes player */
1356   }
1357
1358   /* Yes we're performing a dangerous cast, but it will not be used
1359      unless it's actually a dp3 interface because we will have no
1360      nested groups to delete and we're performing a check below */
1361   context.iface   = (LPDIRECTPLAY3)This;
1362   context.bAnsi   = bAnsi;
1363   context.idGroup = idGroup;
1364
1365   /* We should only concern ourselves with a group having groups if this is
1366      DirectPlay 3 or greater */
1367   if( This->dp3 )
1368   {
1369     /* Remove all links to groups that this group has since this is dp3 */
1370     IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)This, idGroup, NULL, 
1371                                     cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
1372     /* FIXME: Is it allowed to delete a sub group with a parent? Must be */
1373     if( lpGList->lpGData->parent )
1374     {
1375       IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This, 
1376                                          lpGList->lpGData->parent->dpid, 
1377                                          idGroup ); 
1378     } 
1379
1380   }
1381   
1382   /* Remove all players that this group has */
1383   IDirectPlayX_EnumGroupPlayers( (LPDIRECTPLAY3A)This, idGroup, NULL, 
1384                                  cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
1385
1386   /* Now delete this group data and list */
1387   DP_DeleteGroup( This, idGroup ); 
1388
1389   /* Send out a DESTORYPLAYERORGROUP message */
1390
1391   return DP_OK;
1392 }
1393
1394 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1395           ( LPDIRECTPLAY2A iface, DPID idGroup )
1396 {
1397   ICOM_THIS(IDirectPlay2Impl,iface);
1398   return DP_IF_DestroyGroup( This, idGroup, TRUE );
1399 }
1400
1401 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1402           ( LPDIRECTPLAY2 iface, DPID idGroup )
1403 {
1404   ICOM_THIS(IDirectPlay2Impl,iface);
1405   return DP_IF_DestroyGroup( This, idGroup, FALSE );
1406 }
1407
1408 typedef struct _DPFAGContext
1409 {
1410   LPDIRECTPLAY2 iface;
1411   DPID idPlayer;
1412 } DPFAGContext, *lpDPFAGContext;
1413
1414 static HRESULT WINAPI DP_IF_DestroyPlayer
1415           ( IDirectPlay2Impl* This, DPID idPlayer, BOOL bAnsi )
1416 {
1417   DPFAGContext cbContext;
1418
1419   FIXME("(%p)->(0x%08lx,%u): semi stub\n", This, idPlayer, bAnsi );
1420
1421   if( DP_FindPlayer( This, idPlayer ) )
1422   {
1423     return DPERR_INVALIDPLAYER;
1424   }
1425
1426   /* FIXME: If the player is remote, we must be the host to delete this */
1427
1428   cbContext.iface = (LPDIRECTPLAY2)This;
1429   cbContext.idPlayer = idPlayer;
1430
1431   /* Find each group and call DeletePlayerFromGroup if the player is a
1432      member of the group */
1433   IDirectPlayX_EnumGroups( (LPDIRECTPLAY2)This, NULL, cbDeletePlayerFromAllGroups,
1434                            (LPVOID)&cbContext, DPENUMGROUPS_ALL);
1435
1436   /* Now delete player and player list */
1437   DP_DeletePlayer( This, idPlayer );
1438
1439   /* FIXME: Send a DELETEPLAYERORGROUP msg */
1440
1441   return DP_OK;
1442 }
1443
1444 static BOOL
1445 cbDeletePlayerFromAllGroups(
1446     DPID            dpId,
1447     DWORD           dwPlayerType,
1448     LPCDPNAME       lpName,
1449     DWORD           dwFlags,
1450     LPVOID          lpContext )
1451 {
1452   lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1453
1454   if( dwPlayerType == DPPLAYERTYPE_GROUP )
1455   {
1456     IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface, lpCtxt->idPlayer, dpId );
1457
1458     /* Enumerate all groups in this group - yes this is pseudo recursive */
1459     IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)lpCtxt->iface, /*FIXME*/
1460                                     dpId, NULL, 
1461                                     cbDeletePlayerFromAllGroups, 
1462                                     lpContext, DPENUMGROUPS_ALL );
1463   }
1464   else
1465   {
1466     ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
1467   }
1468
1469   return TRUE;
1470 }
1471
1472 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1473           ( LPDIRECTPLAY2A iface, DPID idPlayer )
1474 {
1475   ICOM_THIS(IDirectPlay2Impl,iface);
1476   return DP_IF_DestroyPlayer( This, idPlayer, TRUE );
1477 }
1478
1479 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1480           ( LPDIRECTPLAY2 iface, DPID idPlayer )
1481 {
1482   ICOM_THIS(IDirectPlay2Impl,iface);
1483   return DP_IF_DestroyPlayer( This, idPlayer, FALSE );
1484 }
1485
1486 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1487           ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance, 
1488             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1489             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1490 {
1491   FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): stub\n", 
1492           This, idGroup, lpguidInstance, lpEnumPlayersCallback2, 
1493           lpContext, dwFlags, bAnsi );
1494   return DP_OK;
1495 }
1496
1497 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
1498           ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance, 
1499             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1500             LPVOID lpContext, DWORD dwFlags )
1501 {
1502   ICOM_THIS(IDirectPlay2Impl,iface);
1503   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1504                                lpEnumPlayersCallback2, lpContext,
1505                                dwFlags, TRUE );
1506 }
1507
1508 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
1509           ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance, 
1510             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1511             LPVOID lpContext, DWORD dwFlags )
1512 {
1513   ICOM_THIS(IDirectPlay2Impl,iface);
1514   return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
1515                                lpEnumPlayersCallback2, lpContext,
1516                                dwFlags, FALSE );
1517 }
1518
1519 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
1520 static HRESULT WINAPI DP_IF_EnumGroups
1521           ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
1522             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1523             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1524 {
1525   lpGroupList lpGList;
1526
1527   FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): semi stub\n", 
1528          This, lpguidInstance, lpEnumPlayersCallback2, 
1529          lpContext, dwFlags, bAnsi );
1530
1531   lpGList = This->dp2->groups.lpQHFirst; 
1532
1533   while( lpGList )
1534   {
1535     /* Is this a top level group? */
1536     if( lpGList->lpGData->parent )
1537     {
1538       continue;
1539     }
1540
1541     /* FIXME: Should check dwFlags for match here */
1542
1543     if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
1544                                     &lpGList->lpGData->name, dwFlags, 
1545                                     lpContext ) )
1546     {
1547       break; /* User requested break */
1548     }
1549
1550     if( ( lpGList = lpGList->groups.lpQNext ) == This->dp2->groups.lpQHFirst )
1551     {
1552       break;
1553     }
1554   } 
1555
1556   return DP_OK;
1557 }
1558
1559 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
1560           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, 
1561             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1562             LPVOID lpContext, DWORD dwFlags )
1563 {
1564   ICOM_THIS(IDirectPlay2Impl,iface);
1565   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
1566                          lpContext, dwFlags, TRUE );
1567 }
1568
1569 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
1570           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, 
1571             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1572             LPVOID lpContext, DWORD dwFlags )
1573 {
1574   ICOM_THIS(IDirectPlay2Impl,iface);
1575   return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
1576                          lpContext, dwFlags, FALSE );
1577 }
1578
1579 static HRESULT WINAPI DP_IF_EnumPlayers
1580           ( IDirectPlay2Impl* This, LPGUID lpguidInstance, 
1581             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1582             LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1583 {
1584
1585   FIXME("(%p)->(%p,%p,%p,0x%08lx,%u): stub\n", 
1586           This, lpguidInstance, lpEnumPlayersCallback2, 
1587           lpContext, dwFlags, bAnsi );
1588
1589   return DP_OK;
1590 }
1591
1592 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
1593           ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance, 
1594             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1595             LPVOID lpContext, DWORD dwFlags )
1596 {
1597   ICOM_THIS(IDirectPlay2Impl,iface);
1598   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
1599                           lpContext, dwFlags, TRUE );
1600 }
1601
1602 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
1603           ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance, 
1604             LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, 
1605             LPVOID lpContext, DWORD dwFlags )
1606 {
1607   ICOM_THIS(IDirectPlay2Impl,iface);
1608   return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
1609                           lpContext, dwFlags, FALSE );
1610 }
1611
1612 /* This function should call the registered callback function that the user
1613    passed into EnumSessions for each entry available.
1614  */
1615 static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1616                                      LPVOID lpNSInfo,
1617                                      DWORD dwTimeout,
1618                                      LPVOID lpContext )
1619 {
1620   LPDPSESSIONDESC2 lpSessionDesc;
1621
1622   FIXME( ": not checking for conditions\n" );
1623
1624   NS_ResetSessionEnumeration( lpNSInfo );
1625
1626   /* Enumerate all sessions */
1627   while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
1628   {
1629     TRACE( "EnumSessionsCallback2 invoked\n" );
1630     if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
1631     {
1632       return;
1633     }
1634   }
1635
1636 }
1637
1638 static DWORD CALLBACK DP_EnumSessionsSpwanThreadA( LPVOID lpContext )
1639 {
1640   ICOM_THIS(IDirectPlay2Impl,lpContext);
1641   DWORD dwTimeout = This->dp2->enumSessionAsyncCallbackData.dwTimeout;
1642
1643   TRACE( "(%p)->(0x%08lx)\n", This, dwTimeout );
1644
1645   /* FIXME: Don't think this is exactly right. It'll do for now */
1646   for( ;; )
1647   {
1648     /* 2: Send the broadcast for session enumeration */
1649     NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData );
1650
1651     SleepEx( dwTimeout, FALSE ); 
1652
1653     DP_InvokeEnumSessionCallbacksA( This->dp2->enumSessionAsyncCallbackData.cb,
1654                                     This->dp2->lpNameServerData, 
1655                                     dwTimeout,
1656                                     This->dp2->enumSessionAsyncCallbackData.lpContext );
1657
1658     /* All sessions have been enumerated. Invoke the callback function
1659        once more indicating a timeout has occured. This is the way
1660        that the application can indicate that it wishes to continue with the
1661        enumeration */
1662     if( !(This->dp2->enumSessionAsyncCallbackData.cb)( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext ) )
1663     {
1664       /* The application doesn't want us to continue - end this thread */
1665       return 0;
1666     }
1667
1668   }
1669
1670   return 1;
1671 }
1672
1673 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
1674           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1675             LPVOID lpContext, DWORD dwFlags )
1676 {
1677   ICOM_THIS(IDirectPlay2Impl,iface);
1678
1679   TRACE("(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n", This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
1680
1681   if( dwTimeout == 0 )
1682   {
1683     /* Should actually be getting the dwTimeout value through 
1684        IDirectPlay_GetCaps( This, ...)  */
1685     FIXME( ": should provide a dependent dwTimeout\n" );
1686     dwTimeout = 5 * 1000; /* 5 seconds */
1687   }
1688
1689   if( dwFlags & DPENUMSESSIONS_STOPASYNC )
1690   {
1691     /* Does a thread exist? If so we were doing an async enum session */
1692     if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
1693     {
1694       /* FIXME: This needs to be send an event to the thread to clean itself up nicely */
1695       TerminateThread( This->dp2->hEnumSessionThread, 0 );
1696       CloseHandle( This->dp2->hEnumSessionThread );
1697
1698       This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
1699
1700       This->dp2->enumSessionAsyncCallbackData.cb        = NULL;
1701       This->dp2->enumSessionAsyncCallbackData.lpContext = NULL;
1702       This->dp2->enumSessionAsyncCallbackData.dwTimeout = INFINITE;
1703
1704       return DP_OK;
1705     }
1706   
1707     /* Indicate some sort of error... */
1708     WARN( "STOPASYNC attempted when no async running\n" );  
1709     return DP_OK;
1710   }
1711
1712   /* FIXME: Interface locking sucks in this method */
1713
1714   if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
1715   {
1716     DWORD dwThreadId;
1717  
1718     /* Enumerate everything presently in the local session cache */
1719     DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext );
1720
1721     /* See if we've already created a thread to service this interface */
1722     if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
1723     {
1724       /* FIXME: Should be adding a reference here - another thread now knows
1725                 how to call this interface */
1726       This->dp2->enumSessionAsyncCallbackData.cb        = lpEnumSessionsCallback2;
1727       This->dp2->enumSessionAsyncCallbackData.lpContext = lpContext;
1728       This->dp2->enumSessionAsyncCallbackData.dwTimeout = dwTimeout;
1729
1730       TRACE( ": creating EnumSessions thread\n" );
1731     
1732       This->dp2->hEnumSessionThread = CreateThread( NULL,
1733                                                     0,
1734                                                     DP_EnumSessionsSpwanThreadA,
1735                                                     This,
1736                                                     0,
1737                                                     &dwThreadId );
1738     }
1739
1740   }
1741   else
1742   {
1743     /* Send the broadcast for session enumeration */
1744     NS_SendSessionRequestBroadcast( This->dp2->lpNameServerData );
1745
1746     SleepEx( dwTimeout, FALSE ); 
1747  
1748     DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2, This->dp2->lpNameServerData, dwTimeout, lpContext );
1749   }
1750
1751   return DP_OK;
1752 }
1753
1754 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
1755           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout, LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
1756             LPVOID lpContext, DWORD dwFlags )
1757 {
1758   ICOM_THIS(IDirectPlay2Impl,iface);
1759   FIXME("(%p)->(%p,0x%08lx,%p,%p,0x%08lx): stub\n", This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
1760   return DP_OK;
1761 }
1762
1763 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
1764           ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
1765 {
1766   ICOM_THIS(IDirectPlay2Impl,iface);
1767   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpDPCaps, dwFlags );
1768   return DP_OK;
1769 }
1770
1771 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
1772           ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
1773 {
1774   ICOM_THIS(IDirectPlay2Impl,iface);
1775   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpDPCaps, dwFlags );
1776   return DP_OK;
1777 }
1778
1779 static HRESULT WINAPI DP_IF_GetGroupData
1780           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
1781             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
1782 {
1783   lpGroupList lpGList;
1784
1785   FIXME("(%p)->(0x%08lx,%p,%p,0x%08lx,%u): dwFlags ignored\n", 
1786           This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
1787
1788   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1789   {
1790     return DPERR_INVALIDGROUP;
1791   }
1792
1793   /* Is the user requesting to know how big a buffer is required? */
1794   if( ( lpData == NULL ) ||
1795       ( *lpdwDataSize < lpGList->lpGData->dwDataSize ) 
1796     )
1797   {
1798     *lpdwDataSize = lpGList->lpGData->dwDataSize;
1799     return DPERR_BUFFERTOOSMALL; 
1800   }
1801
1802   memcpy( lpData, lpGList->lpGData->lpData, lpGList->lpGData->dwDataSize );
1803
1804   return DP_OK;
1805 }
1806
1807 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
1808           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
1809             LPDWORD lpdwDataSize, DWORD dwFlags )
1810 {
1811   ICOM_THIS(IDirectPlay2Impl,iface);
1812   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, 
1813                            dwFlags, TRUE );
1814 }
1815
1816 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
1817           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
1818             LPDWORD lpdwDataSize, DWORD dwFlags )
1819 {
1820   ICOM_THIS(IDirectPlay2Impl,iface);
1821   return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize, 
1822                            dwFlags, FALSE );
1823 }
1824
1825 static HRESULT WINAPI DP_IF_GetGroupName
1826           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
1827             LPDWORD lpdwDataSize, BOOL bAnsi )
1828 {
1829   lpGroupList lpGList;
1830   LPDPNAME    lpName = (LPDPNAME)lpData;
1831   DWORD       dwRequiredDataSize;
1832
1833   FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n", 
1834           This, idGroup, lpData, lpdwDataSize, bAnsi );
1835
1836   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1837   {
1838     return DPERR_INVALIDGROUP;
1839   }
1840
1841   dwRequiredDataSize = lpGList->lpGData->name.dwSize;
1842
1843   if( lpGList->lpGData->name.psn.lpszShortNameA )
1844   {
1845     dwRequiredDataSize += strlen( lpGList->lpGData->name.psn.lpszShortNameA ) + 1;
1846   }
1847
1848   if( lpGList->lpGData->name.pln.lpszLongNameA )
1849   {
1850     dwRequiredDataSize += strlen( lpGList->lpGData->name.pln.lpszLongNameA ) + 1;
1851   }
1852  
1853   if( ( lpData == NULL ) ||
1854       ( *lpdwDataSize < dwRequiredDataSize )
1855     )
1856   {
1857     *lpdwDataSize = dwRequiredDataSize;
1858     return DPERR_BUFFERTOOSMALL;
1859   }
1860
1861   /* Copy the structure */
1862   memcpy( lpName, &lpGList->lpGData->name, lpGList->lpGData->name.dwSize );
1863
1864   if( lpGList->lpGData->name.psn.lpszShortNameA )
1865   {
1866     strcpy( ((BYTE*)lpName)+lpGList->lpGData->name.dwSize, 
1867             lpGList->lpGData->name.psn.lpszShortNameA );
1868   }
1869   else
1870   {
1871     lpName->psn.lpszShortNameA = NULL;
1872   }
1873
1874   if( lpGList->lpGData->name.psn.lpszShortNameA )
1875   {
1876     strcpy( ((BYTE*)lpName)+lpGList->lpGData->name.dwSize, 
1877             lpGList->lpGData->name.pln.lpszLongNameA );
1878   }
1879   else
1880   {
1881     lpName->pln.lpszLongNameA = NULL;
1882   }
1883
1884   return DP_OK;
1885 }
1886
1887 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
1888           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
1889             LPDWORD lpdwDataSize )
1890 {
1891   ICOM_THIS(IDirectPlay2Impl,iface);
1892   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
1893 }
1894
1895 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
1896           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
1897             LPDWORD lpdwDataSize )
1898 {
1899   ICOM_THIS(IDirectPlay2Impl,iface);
1900   return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
1901 }
1902
1903 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
1904           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
1905 {
1906   ICOM_THIS(IDirectPlay2Impl,iface);
1907   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwCount );
1908   return DP_OK;
1909 }
1910
1911 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
1912           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
1913 {
1914   ICOM_THIS(IDirectPlay2Impl,iface);
1915   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwCount );
1916   return DP_OK;
1917 }
1918
1919 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
1920           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
1921 {
1922   ICOM_THIS(IDirectPlay2Impl,iface);
1923   FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
1924   return DP_OK;
1925 }
1926
1927 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
1928           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
1929 {
1930   ICOM_THIS(IDirectPlay2Impl,iface);
1931   FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
1932   return DP_OK;
1933 }
1934
1935 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
1936           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, DWORD dwFlags )
1937 {
1938   ICOM_THIS(IDirectPlay2Impl,iface);
1939   FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idPlayer, lpPlayerCaps, dwFlags );
1940   return DP_OK;
1941 }
1942
1943 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
1944           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps, DWORD dwFlags )
1945 {
1946   ICOM_THIS(IDirectPlay2Impl,iface);
1947   FIXME("(%p)->(0x%08lx,%p,0x%08lx): stub\n", This, idPlayer, lpPlayerCaps, dwFlags );
1948   return DP_OK;
1949 }
1950
1951 static HRESULT WINAPI DP_IF_GetPlayerData
1952           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
1953             LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
1954 {
1955   lpPlayerList lpPList;
1956
1957   FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u): stub\n", 
1958          This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
1959
1960   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1961   {
1962     return DPERR_INVALIDPLAYER;
1963   }
1964
1965   /* Is the user requesting to know how big a buffer is required? */
1966   if( ( lpData == NULL ) ||
1967       ( *lpdwDataSize < lpPList->lpPData->dwDataSize )
1968     )
1969   {
1970     *lpdwDataSize = lpPList->lpPData->dwDataSize;
1971     return DPERR_BUFFERTOOSMALL;
1972   }
1973
1974   memcpy( lpData, lpPList->lpPData->lpData, lpPList->lpPData->dwDataSize );
1975
1976   return DP_OK;
1977 }
1978
1979 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
1980           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
1981             LPDWORD lpdwDataSize, DWORD dwFlags )
1982 {
1983   ICOM_THIS(IDirectPlay2Impl,iface);
1984   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, 
1985                             dwFlags, TRUE );
1986 }
1987
1988 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
1989           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
1990             LPDWORD lpdwDataSize, DWORD dwFlags )
1991 {
1992   ICOM_THIS(IDirectPlay2Impl,iface);
1993   return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize, 
1994                             dwFlags, FALSE );
1995 }
1996
1997 static HRESULT WINAPI DP_IF_GetPlayerName
1998           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
1999             LPDWORD lpdwDataSize, BOOL bAnsi )
2000 {
2001   lpPlayerList lpPList;
2002   LPDPNAME    lpName = (LPDPNAME)lpData;
2003   DWORD       dwRequiredDataSize;
2004
2005   FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n", 
2006          This, idPlayer, lpData, lpdwDataSize, bAnsi );
2007
2008   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2009   {
2010     return DPERR_INVALIDPLAYER;
2011   }
2012
2013   dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2014
2015   if( lpPList->lpPData->name.psn.lpszShortNameA )
2016   {
2017     dwRequiredDataSize += strlen( lpPList->lpPData->name.psn.lpszShortNameA ) + 1;
2018   }
2019
2020   if( lpPList->lpPData->name.pln.lpszLongNameA )
2021   {
2022     dwRequiredDataSize += strlen( lpPList->lpPData->name.pln.lpszLongNameA ) + 1;
2023   }
2024
2025   if( ( lpData == NULL ) ||
2026       ( *lpdwDataSize < dwRequiredDataSize )
2027     )
2028   {
2029     *lpdwDataSize = dwRequiredDataSize;
2030     return DPERR_BUFFERTOOSMALL;
2031   }
2032
2033   /* Copy the structure */
2034   memcpy( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2035
2036   if( lpPList->lpPData->name.psn.lpszShortNameA )
2037   {
2038     strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2039             lpPList->lpPData->name.psn.lpszShortNameA );
2040   }
2041   else
2042   {
2043     lpName->psn.lpszShortNameA = NULL;
2044   }
2045
2046   if( lpPList->lpPData->name.psn.lpszShortNameA )
2047   {
2048     strcpy( ((BYTE*)lpName)+lpPList->lpPData->name.dwSize,
2049             lpPList->lpPData->name.pln.lpszLongNameA );
2050   }
2051   else
2052   {
2053     lpName->pln.lpszLongNameA = NULL;
2054   }
2055
2056   return DP_OK;
2057 }
2058
2059 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2060           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
2061             LPDWORD lpdwDataSize )
2062 {
2063   ICOM_THIS(IDirectPlay2Impl,iface);
2064   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2065 }
2066
2067 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2068           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
2069             LPDWORD lpdwDataSize )
2070 {
2071   ICOM_THIS(IDirectPlay2Impl,iface);
2072   return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2073 }
2074
2075 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2076           ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2077 {
2078   ICOM_THIS(IDirectPlay2Impl,iface);
2079   FIXME("(%p)->(%p,%p): stub\n", This, lpData, lpdwDataSize );
2080   return DP_OK;
2081 }
2082
2083 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2084           ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2085 {
2086   ICOM_THIS(IDirectPlay2Impl,iface);
2087   FIXME("(%p)->(%p,%p): stub\n", This, lpData, lpdwDataSize );
2088   return DP_OK;
2089 }
2090
2091 /* Intended only for COM compatibility. Always returns an error. */
2092 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2093           ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2094 {
2095   ICOM_THIS(IDirectPlay2Impl,iface);
2096   TRACE("(%p)->(%p): stub\n", This, lpGUID );
2097   return DPERR_ALREADYINITIALIZED;
2098 }
2099
2100 /* Intended only for COM compatibility. Always returns an error. */
2101 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2102           ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2103 {
2104   ICOM_THIS(IDirectPlay2Impl,iface);
2105   TRACE("(%p)->(%p): stub\n", This, lpGUID );
2106   return DPERR_ALREADYINITIALIZED;
2107 }
2108
2109
2110 static HRESULT WINAPI DP_SecureOpen
2111           ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2112             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
2113 {
2114   FIXME( "(%p)->(%p,0x%08lx,%p,%p): semi stub\n", 
2115          This, lpsd, dwFlags, lpSecurity, lpCredentials );
2116
2117   if( This->dp2->bConnectionOpen )
2118   {
2119     TRACE( ": rejecting already open connection.\n" );
2120     return DPERR_ALREADYINITIALIZED;
2121   }
2122
2123   /* When we open we need to stop any EnumSession activity */
2124   /* FIXME: Perhaps some sort of internal interface would be better */
2125   IDirectPlayX_EnumSessions( (LPDIRECTPLAY2A)This, NULL, 0, NULL, NULL, 
2126                              DPENUMSESSIONS_STOPASYNC ); 
2127
2128   if( dwFlags & DPOPEN_CREATE )
2129   {
2130     dwFlags &= ~DPOPEN_CREATE;
2131
2132     /* Rightoo - this computer is the host and the local computer needs to be
2133        the name server so that others can join this session */
2134     NS_SetLocalComputerAsNameServer( lpsd );
2135
2136     This->dp2->bHostInterface = TRUE;
2137   }
2138
2139   if( dwFlags )
2140   {
2141     ERR( ": ignored dwFlags 0x%08lx\n", dwFlags );
2142   }
2143
2144   return DP_OK;
2145 }
2146
2147 static HRESULT WINAPI DirectPlay2AImpl_Open
2148           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2149 {
2150   ICOM_THIS(IDirectPlay2Impl,iface);
2151   TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2152   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL );
2153 }
2154
2155 static HRESULT WINAPI DirectPlay2WImpl_Open
2156           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2157 {
2158   ICOM_THIS(IDirectPlay2Impl,iface);
2159   TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2160   return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL );
2161 }
2162
2163 static HRESULT WINAPI DirectPlay2AImpl_Receive
2164           ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2165 {
2166   ICOM_THIS(IDirectPlay2Impl,iface);
2167   FIXME("(%p)->(%p,%p,0x%08lx,%p,%p): stub\n", This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize );
2168   return DP_OK;
2169 }
2170
2171 static HRESULT WINAPI DirectPlay2WImpl_Receive
2172           ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2173 {
2174   ICOM_THIS(IDirectPlay2Impl,iface);
2175   FIXME("(%p)->(%p,%p,0x%08lx,%p,%p): stub\n", This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize );
2176   return DP_OK;
2177 }
2178
2179 static HRESULT WINAPI DirectPlay2AImpl_Send
2180           ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2181 {
2182   ICOM_THIS(IDirectPlay2Impl,iface);
2183   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize );
2184   return DP_OK;
2185 }
2186
2187 static HRESULT WINAPI DirectPlay2WImpl_Send
2188           ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2189 {
2190   ICOM_THIS(IDirectPlay2Impl,iface);
2191   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize );
2192   return DP_OK;
2193 }
2194
2195 static HRESULT WINAPI DP_IF_SetGroupData
2196           ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData, 
2197             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2198 {
2199   lpGroupList lpGList;
2200
2201   FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u): dwFlags ignored\n", 
2202          This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
2203
2204   /* Parameter check */
2205   if( ( lpData == NULL ) &&
2206       ( dwDataSize != 0 )
2207     )
2208   {
2209     return DPERR_INVALIDPARAMS;
2210   }
2211
2212   /* Find the pointer to the data for this player */
2213   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2214   {
2215     return DPERR_INVALIDOBJECT;
2216   }
2217
2218   DP_SetGroupData( lpGList->lpGData, lpData, dwDataSize );
2219
2220   return DP_OK;
2221 }
2222
2223 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
2224           ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData, 
2225             DWORD dwDataSize, DWORD dwFlags )
2226 {  
2227   ICOM_THIS(IDirectPlay2Impl,iface);
2228   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
2229 }
2230
2231 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
2232           ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData, 
2233             DWORD dwDataSize, DWORD dwFlags )
2234 {   
2235   ICOM_THIS(IDirectPlay2Impl,iface);
2236   return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
2237 }
2238
2239 static HRESULT WINAPI DP_IF_SetGroupName
2240           ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName, 
2241             DWORD dwFlags, BOOL bAnsi )
2242 {
2243   lpGroupList lpGList;
2244
2245   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup, 
2246          lpGroupName, dwFlags, bAnsi );
2247
2248   if( ( lpGList = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2249   {
2250     return DPERR_INVALIDGROUP;
2251   }
2252
2253   DP_CopyDPNAMEStruct( &lpGList->lpGData->name, lpGroupName, bAnsi );
2254
2255   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2256   FIXME( "Message not sent and dwFlags ignored\n" );
2257
2258   return DP_OK;
2259 }
2260
2261 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
2262           ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName, 
2263             DWORD dwFlags )
2264 {
2265   ICOM_THIS(IDirectPlay2Impl,iface);
2266   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
2267 }
2268
2269 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
2270           ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName, 
2271             DWORD dwFlags )
2272 {
2273   ICOM_THIS(IDirectPlay2Impl,iface);
2274   return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
2275 }
2276
2277 static HRESULT WINAPI DP_IF_SetPlayerData
2278           ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData, 
2279             DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
2280 {
2281   lpPlayerList lpPList;
2282
2283   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n", 
2284          This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
2285
2286   /* Parameter check */
2287   if( ( lpData == NULL ) &&
2288       ( dwDataSize != 0 )
2289     )
2290   {
2291     return DPERR_INVALIDPARAMS;
2292   }
2293
2294   /* Find the pointer to the data for this player */
2295   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2296   {
2297     return DPERR_INVALIDPLAYER;
2298   }
2299
2300   DP_SetPlayerData( lpPList->lpPData, lpData, dwDataSize );
2301
2302   if( !(dwFlags & DPSET_LOCAL ) ) /* Is DPSET_REMOTE? */
2303   {
2304     FIXME( "Change not propagated to all players in the session\n" );
2305   }
2306
2307   return DP_OK;
2308 }
2309
2310 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
2311           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, 
2312             DWORD dwDataSize, DWORD dwFlags )
2313 {
2314   ICOM_THIS(IDirectPlay2Impl,iface);
2315   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, 
2316                               dwFlags, TRUE );
2317 }
2318
2319 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
2320           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, 
2321             DWORD dwDataSize, DWORD dwFlags )
2322 {
2323   ICOM_THIS(IDirectPlay2Impl,iface);
2324   return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize, 
2325                               dwFlags, FALSE );
2326 }
2327
2328 static HRESULT WINAPI DP_IF_SetPlayerName
2329           ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName, 
2330             DWORD dwFlags, BOOL bAnsi )
2331 {
2332   lpPlayerList lpPList;
2333
2334   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", 
2335          This, idPlayer, lpPlayerName, dwFlags, bAnsi );
2336
2337   if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2338   {
2339     return DPERR_INVALIDGROUP;
2340   }
2341
2342   DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
2343
2344   /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
2345   FIXME( "Message not sent and dwFlags ignored\n" );
2346
2347   return DP_OK;
2348 }
2349
2350 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
2351           ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName, 
2352             DWORD dwFlags )
2353 {
2354   ICOM_THIS(IDirectPlay2Impl,iface);
2355   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
2356 }
2357
2358 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
2359           ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName, 
2360             DWORD dwFlags )
2361 {
2362   ICOM_THIS(IDirectPlay2Impl,iface);
2363   return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
2364 }
2365
2366 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
2367           ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
2368 {
2369   ICOM_THIS(IDirectPlay2Impl,iface);
2370   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpSessDesc, dwFlags );
2371   return DP_OK;
2372 }
2373
2374 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
2375           ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
2376 {
2377   ICOM_THIS(IDirectPlay2Impl,iface);
2378   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpSessDesc, dwFlags );
2379   return DP_OK;
2380 }
2381
2382 static HRESULT WINAPI DP_IF_AddGroupToGroup
2383           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
2384 {
2385   lpGroupList lpGParentList;
2386   lpGroupList lpGList;
2387   lpGroupList lpNewGList;
2388
2389   TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
2390
2391   if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
2392   {
2393     return DPERR_INVALIDGROUP;
2394   }
2395
2396   if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
2397   {
2398     return DPERR_INVALIDGROUP;
2399   }
2400  
2401   /* Create a player list (ie "shortcut" ) */
2402   lpNewGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2403                                        sizeof( *lpNewGList ) );
2404   if( lpNewGList == NULL )
2405   {
2406     return DPERR_CANTADDPLAYER;
2407   }  
2408
2409   /* Add the shortcut */
2410   lpNewGList->lpGData = lpGList->lpGData;
2411
2412   /* Add the player to the list of players for this group */
2413   DPQ_INSERT( lpGList->lpGData->groups, lpNewGList, groups );
2414
2415   /* Send a ADDGROUPTOGROUP message */
2416   FIXME( "Not sending message\n" );
2417   
2418   return DP_OK;
2419 }
2420
2421 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
2422           ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
2423 {
2424   ICOM_THIS(IDirectPlay3Impl,iface);
2425   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
2426 }
2427
2428 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
2429           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
2430 {
2431   ICOM_THIS(IDirectPlay3Impl,iface);
2432   return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
2433 }
2434
2435 static HRESULT WINAPI DP_IF_CreateGroupInGroup
2436           ( IDirectPlay3Impl* This, DPID idParentGroup, LPDPID lpidGroup, 
2437             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
2438             DWORD dwFlags )
2439 {
2440   lpGroupList lpGParentList;
2441   lpGroupList lpGList;
2442   lpGroupData lpGData;
2443
2444   TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx)\n", 
2445          This, idParentGroup, lpidGroup, lpGroupName, lpData, 
2446          dwDataSize, dwFlags );
2447
2448   /* Verify that the specified parent is valid */
2449   if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, 
2450                                          idParentGroup ) ) == NULL 
2451     )
2452   {
2453     return DPERR_INVALIDGROUP;
2454   } 
2455
2456   lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName, 
2457                             lpGParentList->lpGData, TRUE /* Ansi */ );
2458
2459   if( lpGData == NULL )
2460   {
2461     return DPERR_CANTADDPLAYER; /* yes player not group */
2462   }
2463   
2464   DP_SetGroupData( lpGData, lpData, dwDataSize );
2465
2466   /* The list has now been inserted into the interface group list. We now
2467      need to put a "shortcut" to this group in the parent group */
2468   lpGList = (lpGroupList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
2469                                     sizeof( *lpGList ) );
2470   if( lpGList == NULL )
2471   {
2472     FIXME( "Memory leak\n" );
2473     return DPERR_CANTADDPLAYER; /* yes player not group */
2474   }
2475
2476   lpGList->lpGData = lpGData; 
2477
2478   DPQ_INSERT( lpGParentList->lpGData->groups, lpGList, groups );
2479  
2480
2481   /* FIXME: Should send DPMSG_CREATEPLAYERORGROUP message to everyone,
2482             local and remote, that belongs to this session. This will not
2483             be done by calling SetPlayerData */
2484   FIXME( "Should broadcast group creation to everything in session\n" );
2485
2486   return DP_OK;
2487 }
2488
2489 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
2490           ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup, 
2491             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
2492             DWORD dwFlags )
2493 {
2494   ICOM_THIS(IDirectPlay3Impl,iface);
2495   return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName,
2496                                    lpData, dwDataSize, dwFlags );
2497 }
2498
2499 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
2500           ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup, 
2501             LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize, 
2502             DWORD dwFlags )
2503 {
2504   ICOM_THIS(IDirectPlay3Impl,iface);
2505   return DP_IF_CreateGroupInGroup( This, idParentGroup, lpidGroup, lpGroupName,
2506                                    lpData, dwDataSize, dwFlags );
2507 }
2508
2509 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
2510           ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
2511 {
2512   lpGroupList lpGList;
2513   lpGroupList lpGParentList;
2514
2515   TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
2516
2517   /* Is the parent group valid? */
2518   if( ( lpGParentList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
2519   {
2520     return DPERR_INVALIDGROUP;
2521   } 
2522
2523   /* Remove the group from the parent group queue */
2524   DPQ_REMOVE_ENTRY( lpGParentList->lpGData->groups, groups, lpGData->dpid, idGroup, lpGList );
2525
2526   if( lpGList == NULL )
2527   {
2528     return DPERR_INVALIDGROUP;
2529   }
2530
2531   /* Free up the list item */
2532   HeapFree( GetProcessHeap(), 0, lpGList ); 
2533
2534   /* Should send a DELETEGROUPFROMGROUP message */
2535   FIXME( "message not sent\n" );
2536
2537   return DP_OK;
2538 }
2539
2540 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
2541           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
2542 {
2543   ICOM_THIS(IDirectPlay3Impl,iface);
2544   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
2545 }
2546
2547 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
2548           ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
2549 {
2550   ICOM_THIS(IDirectPlay3Impl,iface);
2551   return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
2552 }
2553
2554 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
2555           ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
2556 {
2557   ICOM_THIS(IDirectPlay3Impl,iface);
2558   TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
2559
2560   /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
2561   if( dwFlags == 0 )
2562   {
2563     dwFlags = DPCONNECTION_DIRECTPLAY;
2564   }
2565
2566   if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
2567           ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
2568     ) 
2569   {
2570     return DPERR_INVALIDFLAGS;
2571   }
2572
2573   if( !lpEnumCallback || !*lpEnumCallback )
2574   {
2575      return DPERR_INVALIDPARAMS;
2576   }
2577
2578   /* Enumerate DirectPlay service providers */
2579   if( dwFlags & DPCONNECTION_DIRECTPLAY )
2580   {
2581     HKEY hkResult;
2582     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
2583     LPSTR guidDataSubKey   = "Guid";
2584     char subKeyName[51]; 
2585     DWORD dwIndex, sizeOfSubKeyName=50;
2586     FILETIME filetime;
2587
2588     /* Need to loop over the service providers in the registry */
2589     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
2590                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
2591     {
2592       /* Hmmm. Does this mean that there are no service providers? */
2593       ERR(": no service providers?\n");
2594       return DP_OK;
2595     }
2596
2597
2598     /* Traverse all the service providers we have available */
2599     for( dwIndex=0;
2600          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, 
2601                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
2602          ++dwIndex, sizeOfSubKeyName=51 )
2603     {
2604
2605       HKEY     hkServiceProvider;
2606       GUID     serviceProviderGUID;
2607       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
2608       char     returnBuffer[51];
2609       LPWSTR   lpWGUIDString;
2610       DPNAME   dpName;
2611       HRESULT  hr;
2612
2613       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
2614       LPVOID                   lpAddressBuffer = NULL;
2615       DWORD                    dwAddressBufferSize = 0;
2616
2617       TRACE(" this time through: %s\n", subKeyName );
2618
2619       /* Get a handle for this particular service provider */
2620       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
2621                          &hkServiceProvider ) != ERROR_SUCCESS )
2622       {
2623          ERR(": what the heck is going on?\n" );
2624          continue;
2625       }
2626
2627       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
2628                             NULL, &returnTypeGUID, returnBuffer,
2629                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
2630       {
2631         ERR(": missing GUID registry data members\n" );
2632         continue;
2633       }
2634
2635       /* FIXME: Check return types to ensure we're interpreting data right */
2636       lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer );
2637       CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID );
2638       HeapFree( GetProcessHeap(), 0, lpWGUIDString );
2639       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
2640
2641       /* Fill in the DPNAME struct for the service provider */
2642       dpName.dwSize             = sizeof( dpName );
2643       dpName.dwFlags            = 0;
2644       dpName.psn.lpszShortNameA = subKeyName;
2645       dpName.pln.lpszLongNameA  = NULL;
2646
2647       /* Create the compound address for the service provider. 
2648          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
2649                nast stuff. This may be why the native dll just gets around this little bit by
2650                allocating an 80 byte buffer which isn't even a filled with a valid compound 
2651                address. Oh well. Creating a proper compound address is the way to go anyways 
2652                despite this method taking slightly more heap space and realtime :) */
2653       dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
2654       dpCompoundAddress.dwDataSize   = sizeof( GUID );
2655       dpCompoundAddress.lpData       = &serviceProviderGUID; 
2656
2657       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, 
2658                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
2659       {
2660         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
2661         return hr;
2662       }
2663
2664       /* Now allocate the buffer */
2665       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
2666
2667       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
2668                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
2669       {
2670         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
2671         return hr;
2672       }
2673
2674       /* The enumeration will return FALSE if we are not to continue */
2675       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize, 
2676                            &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
2677       {
2678          WARN("lpEnumCallback returning FALSE\n" );
2679
2680          return DP_OK;
2681       }
2682     }
2683   }
2684
2685   /* Enumerate DirectPlayLobby service providers */
2686   if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
2687   {
2688     HKEY hkResult;
2689     LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
2690     LPSTR guidDataSubKey   = "Guid";
2691     char subKeyName[51]; 
2692     DWORD dwIndex, sizeOfSubKeyName=50;
2693     FILETIME filetime;
2694
2695     /* Need to loop over the service providers in the registry */
2696     if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
2697                          0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
2698     {
2699       /* Hmmm. Does this mean that there are no service providers? */
2700       ERR(": no service providers?\n");
2701       return DP_OK;
2702     }
2703
2704
2705     /* Traverse all the service providers we have available */
2706     for( dwIndex=0;
2707          RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, 
2708                         NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
2709          ++dwIndex, sizeOfSubKeyName=51 )
2710     {
2711
2712       HKEY     hkServiceProvider;
2713       GUID     serviceProviderGUID;
2714       DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
2715       char     returnBuffer[51];
2716       LPWSTR   lpWGUIDString;
2717       DPNAME   dpName;
2718       HRESULT  hr;
2719
2720       DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
2721       LPVOID                   lpAddressBuffer = NULL;
2722       DWORD                    dwAddressBufferSize = 0;
2723
2724       TRACE(" this time through: %s\n", subKeyName );
2725
2726       /* Get a handle for this particular service provider */
2727       if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
2728                          &hkServiceProvider ) != ERROR_SUCCESS )
2729       {
2730          ERR(": what the heck is going on?\n" );
2731          continue;
2732       }
2733
2734       if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
2735                             NULL, &returnTypeGUID, returnBuffer,
2736                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
2737       {
2738         ERR(": missing GUID registry data members\n" );
2739         continue;
2740       }
2741
2742       /* FIXME: Check return types to ensure we're interpreting data right */
2743       lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer );
2744       CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID );
2745       HeapFree( GetProcessHeap(), 0, lpWGUIDString );
2746       /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
2747
2748       /* Fill in the DPNAME struct for the service provider */
2749       dpName.dwSize             = sizeof( dpName );
2750       dpName.dwFlags            = 0;
2751       dpName.psn.lpszShortNameA = subKeyName;
2752       dpName.pln.lpszLongNameA  = NULL;
2753
2754       /* Create the compound address for the service provider. 
2755          NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
2756                nast stuff. This may be why the native dll just gets around this little bit by
2757                allocating an 80 byte buffer which isn't even a filled with a valid compound 
2758                address. Oh well. Creating a proper compound address is the way to go anyways 
2759                despite this method taking slightly more heap space and realtime :) */
2760       dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
2761       dpCompoundAddress.dwDataSize   = sizeof( GUID );
2762       dpCompoundAddress.lpData       = &serviceProviderGUID; 
2763
2764       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer, 
2765                                      &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
2766       {
2767         ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
2768         return hr;
2769       }
2770
2771       /* Now allocate the buffer */
2772       lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
2773
2774       if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
2775                                      &dwAddressBufferSize, TRUE ) ) != DP_OK )
2776       {
2777         ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
2778         return hr;
2779       }
2780
2781       /* The enumeration will return FALSE if we are not to continue */
2782       if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
2783                            &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
2784       {
2785          WARN("lpEnumCallback returning FALSE\n" );
2786
2787          return DP_OK;
2788       }
2789     }
2790   }
2791
2792   return DP_OK;
2793 }
2794
2795 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
2796           ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
2797
2798   ICOM_THIS(IDirectPlay3Impl,iface);
2799   FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
2800   return DP_OK;
2801 }
2802
2803 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
2804           ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
2805 {
2806   lpGroupList lpGList;
2807   lpGroupList lpGiGList;
2808   ICOM_THIS(IDirectPlay3AImpl,iface);
2809
2810   FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): semi stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
2811
2812   if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL ) 
2813   {
2814     return DPERR_INVALIDGROUP;
2815   }
2816
2817   lpGiGList = lpGList->lpGData->groups.lpQHFirst;
2818
2819   while( lpGiGList )
2820   {
2821      /* FIXME: Should check dwFlags for match here */
2822
2823      if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
2824                                      &lpGList->lpGData->name, dwFlags,
2825                                      lpContext ) )
2826      {
2827        return DP_OK; /* User requested break */
2828      }
2829
2830      if( ( lpGiGList = lpGiGList->groups.lpQNext ) == lpGList->lpGData->groups.lpQHFirst )
2831      {
2832         return DP_OK; /* End of groups */
2833      }
2834   }
2835
2836   return DP_OK;
2837 }
2838
2839 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
2840           ( LPDIRECTPLAY3 iface, DPID idGroup, LPGUID lpguidInstance, LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext, DWORD dwFlags )
2841 {
2842   ICOM_THIS(IDirectPlay3Impl,iface);
2843   FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx): stub\n", This, idGroup, lpguidInstance, lpEnumPlayersCallback2, lpContext, dwFlags );
2844   return DP_OK;
2845 }
2846
2847 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
2848           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
2849 {
2850   ICOM_THIS(IDirectPlay3Impl,iface);
2851   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
2852   return DP_OK;
2853 }
2854
2855 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
2856           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
2857 {
2858   ICOM_THIS(IDirectPlay3Impl,iface);
2859   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
2860   return DP_OK;
2861 }
2862
2863 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
2864           ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
2865 {
2866   HMODULE hServiceProvider;
2867   /*DWORD   dwReturnValue; */
2868   typedef DWORD (WINAPI *SP_SPInit)(LPVOID, LPVOID, LPVOID ); /* FIXME: How many arguments? */
2869   SP_SPInit SPInit;
2870
2871   ICOM_THIS(IDirectPlay3Impl,iface);
2872
2873   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags );
2874
2875   if( dwFlags != 0 )
2876   {
2877     return DPERR_INVALIDFLAGS;
2878   }
2879
2880   if( This->dp3->bConnectionInitialized == TRUE )
2881   {
2882     return DPERR_ALREADYINITIALIZED;
2883   }
2884
2885   /* Parse lpConnection as a compound address for the service provider */
2886   /* Take service provider GUID and find the path to it */
2887
2888   /* FIXME: Hard coded to only load the tcp/ip service provider for now... */
2889   hServiceProvider = LoadLibraryA( "dpwsockx.dll" );
2890
2891   if( hServiceProvider == 0 )
2892   {
2893     ERR( "Unable to load service provider\n" );
2894     return DPERR_UNAVAILABLE; 
2895   }
2896   
2897   /* Initialize the service provider by calling SPInit */
2898   SPInit = (SP_SPInit)GetProcAddress( hServiceProvider, "SPInit" );
2899
2900   if( SPInit == NULL )
2901   {
2902     ERR( "Service provider doesn't provide SPInit interface?\n" );
2903   }  
2904
2905 #if 0
2906   /* NOTE: This will crash until I know what parameters/interface this has */
2907   /* FIXME: Take a guess that we just pass the compound address to the SP */
2908   /* Hmmm...how to say which parameters need to be gotten from the SP. They must
2909      come from the compound address, but how do we communicate what's required? */
2910   dwReturnValue = (*SPInit)( lpConnection, NULL, NULL );
2911 #endif
2912
2913   /* This interface is now initialized */
2914   This->dp3->bConnectionInitialized = TRUE;
2915
2916   return DP_OK;
2917 }
2918
2919 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
2920           ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
2921 {
2922   ICOM_THIS(IDirectPlay3Impl,iface);
2923   FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags );
2924   return DP_OK;
2925 }
2926
2927 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
2928           ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, 
2929             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
2930 {
2931   ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
2932   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials );
2933 }
2934
2935 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
2936           ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags, 
2937             LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
2938 {   
2939   ICOM_THIS(IDirectPlay2Impl,iface); /* Yes a dp 2 interface */
2940   return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials );
2941 }
2942
2943 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
2944           ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
2945 {
2946   ICOM_THIS(IDirectPlay3Impl,iface);
2947   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
2948   return DP_OK;
2949 }
2950
2951 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
2952           ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
2953 {
2954   ICOM_THIS(IDirectPlay3Impl,iface);
2955   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
2956   return DP_OK;
2957 }
2958
2959 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
2960           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
2961 {
2962   ICOM_THIS(IDirectPlay3Impl,iface);
2963   FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
2964   return DP_OK;
2965 }
2966
2967 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
2968           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
2969 {
2970   ICOM_THIS(IDirectPlay3Impl,iface);
2971   FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
2972   return DP_OK;
2973 }
2974
2975 static HRESULT WINAPI DirectPlay3AImpl_StartSession
2976           ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
2977 {
2978   ICOM_THIS(IDirectPlay3Impl,iface);
2979   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
2980   return DP_OK;
2981 }
2982
2983 static HRESULT WINAPI DirectPlay3WImpl_StartSession
2984           ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
2985 {
2986   ICOM_THIS(IDirectPlay3Impl,iface);
2987   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
2988   return DP_OK;
2989 }
2990  
2991 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
2992           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
2993 {
2994   ICOM_THIS(IDirectPlay3Impl,iface);
2995   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
2996   return DP_OK;
2997 }
2998
2999 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
3000           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
3001 {
3002   ICOM_THIS(IDirectPlay3Impl,iface);
3003   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
3004   return DP_OK;
3005 }
3006
3007 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
3008           ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
3009 {
3010   lpGroupList lpGList;
3011
3012   ICOM_THIS(IDirectPlay3AImpl,iface);
3013
3014   TRACE("(%p)->(0x%08lx,%p)\n", This, idGroup, lpidGroup );
3015
3016   if( ( lpGList = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3017   {
3018     return DPERR_INVALIDGROUP;
3019   }
3020
3021   *lpidGroup = lpGList->lpGData->dpid;
3022
3023   return DP_OK;
3024 }
3025
3026 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
3027           ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
3028 {
3029   ICOM_THIS(IDirectPlay3Impl,iface);
3030   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroup );
3031   return DP_OK;
3032 }
3033
3034 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
3035           ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3036 {
3037   ICOM_THIS(IDirectPlay3Impl,iface);
3038   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
3039   return DP_OK;
3040 }
3041
3042 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
3043           ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3044 {
3045   ICOM_THIS(IDirectPlay3Impl,iface);
3046   FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
3047   return DP_OK;
3048 }
3049
3050 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
3051           ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
3052 {
3053   ICOM_THIS(IDirectPlay3Impl,iface);
3054   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
3055   return DP_OK;
3056 }
3057
3058 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
3059           ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
3060 {
3061   ICOM_THIS(IDirectPlay3Impl,iface);
3062   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
3063   return DP_OK;
3064 }
3065
3066 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
3067           ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
3068 {
3069   ICOM_THIS(IDirectPlay4Impl,iface);
3070   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
3071   return DP_OK;
3072 }
3073
3074 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
3075           ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
3076 {
3077   ICOM_THIS(IDirectPlay4Impl,iface);
3078   FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
3079   return DP_OK;
3080 }
3081
3082 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
3083           ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
3084 {
3085   ICOM_THIS(IDirectPlay4Impl,iface);
3086   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
3087   return DP_OK;
3088 }
3089
3090 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
3091           ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
3092 {
3093   ICOM_THIS(IDirectPlay4Impl,iface);
3094   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
3095   return DP_OK;
3096 }
3097
3098 static HRESULT WINAPI DirectPlay4AImpl_SendEx
3099           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, LPVOID lpContext, LPDWORD lpdwMsgID )
3100 {
3101   ICOM_THIS(IDirectPlay4Impl,iface);
3102   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, dwTimeout, lpContext, lpdwMsgID );
3103   return DP_OK;
3104 }
3105
3106 static HRESULT WINAPI DirectPlay4WImpl_SendEx
3107           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout, LPVOID lpContext, LPDWORD lpdwMsgID )
3108 {
3109   ICOM_THIS(IDirectPlay4Impl,iface);
3110   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority, dwTimeout, lpContext, lpdwMsgID );
3111   return DP_OK;
3112 }
3113
3114 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
3115           ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
3116 {
3117   ICOM_THIS(IDirectPlay4Impl,iface);
3118   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes );
3119   return DP_OK;
3120 }
3121
3122 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
3123           ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
3124 {
3125   ICOM_THIS(IDirectPlay4Impl,iface);
3126   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p): stub\n", This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes );
3127   return DP_OK;
3128 }
3129
3130 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
3131           ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
3132 {
3133   ICOM_THIS(IDirectPlay4Impl,iface);
3134   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwMsgID, dwFlags );
3135   return DP_OK;
3136 }
3137
3138 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
3139           ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
3140 {
3141   ICOM_THIS(IDirectPlay4Impl,iface);
3142   FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwMsgID, dwFlags );
3143   return DP_OK;
3144 }
3145
3146 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
3147           ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority, DWORD dwFlags )
3148 {
3149   ICOM_THIS(IDirectPlay4Impl,iface);
3150   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx): stub\n", This, dwMinPriority, dwMaxPriority, dwFlags );
3151   return DP_OK;
3152 }
3153
3154 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
3155           ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority, DWORD dwFlags )
3156 {
3157   ICOM_THIS(IDirectPlay4Impl,iface);
3158   FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx): stub\n", This, dwMinPriority, dwMaxPriority, dwFlags );
3159   return DP_OK;
3160 }
3161
3162 /* Note: Hack so we can reuse the old functions without compiler warnings */
3163 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3164 # define XCAST(fun)     (typeof(directPlay2WVT.fn##fun))
3165 #else
3166 # define XCAST(fun)     (void*)
3167 #endif
3168
3169 static ICOM_VTABLE(IDirectPlay2) directPlay2WVT = 
3170 {
3171   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3172   DirectPlay2W_QueryInterface,
3173   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3174   XCAST(Release)DirectPlay2AImpl_Release,
3175
3176   DirectPlay2WImpl_AddPlayerToGroup,
3177   DirectPlay2WImpl_Close,
3178   DirectPlay2WImpl_CreateGroup,
3179   DirectPlay2WImpl_CreatePlayer,
3180   DirectPlay2WImpl_DeletePlayerFromGroup,
3181   DirectPlay2WImpl_DestroyGroup,
3182   DirectPlay2WImpl_DestroyPlayer,
3183   DirectPlay2WImpl_EnumGroupPlayers,
3184   DirectPlay2WImpl_EnumGroups,
3185   DirectPlay2WImpl_EnumPlayers,
3186   DirectPlay2WImpl_EnumSessions,
3187   DirectPlay2WImpl_GetCaps,
3188   DirectPlay2WImpl_GetGroupData,
3189   DirectPlay2WImpl_GetGroupName,
3190   DirectPlay2WImpl_GetMessageCount,
3191   DirectPlay2WImpl_GetPlayerAddress,
3192   DirectPlay2WImpl_GetPlayerCaps,
3193   DirectPlay2WImpl_GetPlayerData,
3194   DirectPlay2WImpl_GetPlayerName,
3195   DirectPlay2WImpl_GetSessionDesc,
3196   DirectPlay2WImpl_Initialize,
3197   DirectPlay2WImpl_Open,
3198   DirectPlay2WImpl_Receive,
3199   DirectPlay2WImpl_Send,
3200   DirectPlay2WImpl_SetGroupData,
3201   DirectPlay2WImpl_SetGroupName,
3202   DirectPlay2WImpl_SetPlayerData,
3203   DirectPlay2WImpl_SetPlayerName,
3204   DirectPlay2WImpl_SetSessionDesc
3205 };
3206 #undef XCAST
3207
3208 /* Note: Hack so we can reuse the old functions without compiler warnings */
3209 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3210 # define XCAST(fun)     (typeof(directPlay2AVT.fn##fun))
3211 #else
3212 # define XCAST(fun)     (void*)
3213 #endif
3214
3215 static ICOM_VTABLE(IDirectPlay2) directPlay2AVT = 
3216 {
3217   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3218   DirectPlay2A_QueryInterface,
3219   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3220   XCAST(Release)DirectPlay2AImpl_Release,
3221
3222   DirectPlay2AImpl_AddPlayerToGroup,
3223   DirectPlay2AImpl_Close,
3224   DirectPlay2AImpl_CreateGroup,
3225   DirectPlay2AImpl_CreatePlayer,
3226   DirectPlay2AImpl_DeletePlayerFromGroup,
3227   DirectPlay2AImpl_DestroyGroup,
3228   DirectPlay2AImpl_DestroyPlayer,
3229   DirectPlay2AImpl_EnumGroupPlayers,
3230   DirectPlay2AImpl_EnumGroups,
3231   DirectPlay2AImpl_EnumPlayers,
3232   DirectPlay2AImpl_EnumSessions,
3233   DirectPlay2AImpl_GetCaps,
3234   DirectPlay2AImpl_GetGroupData,
3235   DirectPlay2AImpl_GetGroupName,
3236   DirectPlay2AImpl_GetMessageCount,
3237   DirectPlay2AImpl_GetPlayerAddress,
3238   DirectPlay2AImpl_GetPlayerCaps,
3239   DirectPlay2AImpl_GetPlayerData,
3240   DirectPlay2AImpl_GetPlayerName,
3241   DirectPlay2AImpl_GetSessionDesc,
3242   DirectPlay2AImpl_Initialize,
3243   DirectPlay2AImpl_Open,
3244   DirectPlay2AImpl_Receive,
3245   DirectPlay2AImpl_Send,
3246   DirectPlay2AImpl_SetGroupData,
3247   DirectPlay2AImpl_SetGroupName,
3248   DirectPlay2AImpl_SetPlayerData,
3249   DirectPlay2AImpl_SetPlayerName,
3250   DirectPlay2AImpl_SetSessionDesc
3251 };
3252 #undef XCAST
3253
3254
3255 /* Note: Hack so we can reuse the old functions without compiler warnings */
3256 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3257 # define XCAST(fun)     (typeof(directPlay3AVT.fn##fun))
3258 #else
3259 # define XCAST(fun)     (void*)
3260 #endif
3261
3262 static ICOM_VTABLE(IDirectPlay3) directPlay3AVT = 
3263 {
3264   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3265   DirectPlay3AImpl_QueryInterface,
3266   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3267   XCAST(Release)DirectPlay2AImpl_Release,
3268
3269   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
3270   XCAST(Close)DirectPlay2AImpl_Close,
3271   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
3272   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
3273   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
3274   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
3275   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
3276   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
3277   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
3278   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
3279   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
3280   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
3281   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
3282   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
3283   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
3284   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
3285   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
3286   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
3287   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
3288   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
3289   XCAST(Initialize)DirectPlay2AImpl_Initialize,
3290   XCAST(Open)DirectPlay2AImpl_Open,
3291   XCAST(Receive)DirectPlay2AImpl_Receive,
3292   XCAST(Send)DirectPlay2AImpl_Send,
3293   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
3294   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
3295   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
3296   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
3297   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
3298
3299   DirectPlay3AImpl_AddGroupToGroup,
3300   DirectPlay3AImpl_CreateGroupInGroup,
3301   DirectPlay3AImpl_DeleteGroupFromGroup,
3302   DirectPlay3AImpl_EnumConnections,
3303   DirectPlay3AImpl_EnumGroupsInGroup,
3304   DirectPlay3AImpl_GetGroupConnectionSettings,
3305   DirectPlay3AImpl_InitializeConnection,
3306   DirectPlay3AImpl_SecureOpen,
3307   DirectPlay3AImpl_SendChatMessage,
3308   DirectPlay3AImpl_SetGroupConnectionSettings,
3309   DirectPlay3AImpl_StartSession,
3310   DirectPlay3AImpl_GetGroupFlags,
3311   DirectPlay3AImpl_GetGroupParent,
3312   DirectPlay3AImpl_GetPlayerAccount,
3313   DirectPlay3AImpl_GetPlayerFlags
3314 };
3315 #undef XCAST
3316
3317 /* Note: Hack so we can reuse the old functions without compiler warnings */
3318 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3319 # define XCAST(fun)     (typeof(directPlay3WVT.fn##fun))
3320 #else
3321 # define XCAST(fun)     (void*)
3322 #endif
3323 static ICOM_VTABLE(IDirectPlay3) directPlay3WVT = 
3324 {
3325   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3326   DirectPlay3WImpl_QueryInterface,
3327   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3328   XCAST(Release)DirectPlay2AImpl_Release,
3329
3330   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
3331   XCAST(Close)DirectPlay2WImpl_Close,
3332   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
3333   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
3334   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
3335   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
3336   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
3337   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
3338   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
3339   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
3340   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
3341   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
3342   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
3343   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
3344   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
3345   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
3346   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
3347   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
3348   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
3349   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
3350   XCAST(Initialize)DirectPlay2WImpl_Initialize,
3351   XCAST(Open)DirectPlay2WImpl_Open,
3352   XCAST(Receive)DirectPlay2WImpl_Receive,
3353   XCAST(Send)DirectPlay2WImpl_Send,
3354   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
3355   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
3356   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
3357   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
3358   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
3359
3360   DirectPlay3WImpl_AddGroupToGroup,
3361   DirectPlay3WImpl_CreateGroupInGroup,
3362   DirectPlay3WImpl_DeleteGroupFromGroup,
3363   DirectPlay3WImpl_EnumConnections,
3364   DirectPlay3WImpl_EnumGroupsInGroup,
3365   DirectPlay3WImpl_GetGroupConnectionSettings,
3366   DirectPlay3WImpl_InitializeConnection,
3367   DirectPlay3WImpl_SecureOpen,
3368   DirectPlay3WImpl_SendChatMessage,
3369   DirectPlay3WImpl_SetGroupConnectionSettings,
3370   DirectPlay3WImpl_StartSession,
3371   DirectPlay3WImpl_GetGroupFlags,
3372   DirectPlay3WImpl_GetGroupParent,
3373   DirectPlay3WImpl_GetPlayerAccount,
3374   DirectPlay3WImpl_GetPlayerFlags
3375 };
3376 #undef XCAST
3377
3378 /* Note: Hack so we can reuse the old functions without compiler warnings */
3379 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3380 # define XCAST(fun)     (typeof(directPlay4WVT.fn##fun))
3381 #else
3382 # define XCAST(fun)     (void*)
3383 #endif
3384 static ICOM_VTABLE(IDirectPlay4) directPlay4WVT =
3385 {
3386   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3387   DirectPlay4WImpl_QueryInterface,
3388   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3389   XCAST(Release)DirectPlay2AImpl_Release,
3390
3391   XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
3392   XCAST(Close)DirectPlay2WImpl_Close,
3393   XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
3394   XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
3395   XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
3396   XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
3397   XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
3398   XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
3399   XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
3400   XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
3401   XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
3402   XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
3403   XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
3404   XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
3405   XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
3406   XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
3407   XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
3408   XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
3409   XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
3410   XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
3411   XCAST(Initialize)DirectPlay2WImpl_Initialize,
3412   XCAST(Open)DirectPlay2WImpl_Open,
3413   XCAST(Receive)DirectPlay2WImpl_Receive,
3414   XCAST(Send)DirectPlay2WImpl_Send,
3415   XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
3416   XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
3417   XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
3418   XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
3419   XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
3420
3421   XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
3422   XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
3423   XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
3424   XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
3425   XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
3426   XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
3427   XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
3428   XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
3429   XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
3430   XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
3431   XCAST(StartSession)DirectPlay3WImpl_StartSession,
3432   XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
3433   XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
3434   XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
3435   XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
3436
3437   DirectPlay4WImpl_GetGroupOwner,
3438   DirectPlay4WImpl_SetGroupOwner,
3439   DirectPlay4WImpl_SendEx,
3440   DirectPlay4WImpl_GetMessageQueue,
3441   DirectPlay4WImpl_CancelMessage,
3442   DirectPlay4WImpl_CancelPriority
3443 };
3444 #undef XCAST
3445
3446
3447 /* Note: Hack so we can reuse the old functions without compiler warnings */
3448 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
3449 # define XCAST(fun)     (typeof(directPlay4AVT.fn##fun))
3450 #else
3451 # define XCAST(fun)     (void*)
3452 #endif
3453 static ICOM_VTABLE(IDirectPlay4) directPlay4AVT =
3454 {
3455   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3456   DirectPlay4AImpl_QueryInterface,
3457   XCAST(AddRef)DirectPlay2AImpl_AddRef,
3458   XCAST(Release)DirectPlay2AImpl_Release,
3459
3460   XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
3461   XCAST(Close)DirectPlay2AImpl_Close,
3462   XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
3463   XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
3464   XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
3465   XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
3466   XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
3467   XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
3468   XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
3469   XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
3470   XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
3471   XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
3472   XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
3473   XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
3474   XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
3475   XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
3476   XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
3477   XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
3478   XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
3479   XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
3480   XCAST(Initialize)DirectPlay2AImpl_Initialize,
3481   XCAST(Open)DirectPlay2AImpl_Open,
3482   XCAST(Receive)DirectPlay2AImpl_Receive,
3483   XCAST(Send)DirectPlay2AImpl_Send,
3484   XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
3485   XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
3486   XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
3487   XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
3488   XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
3489
3490   XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
3491   XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
3492   XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
3493   XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
3494   XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
3495   XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
3496   XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
3497   XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
3498   XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
3499   XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
3500   XCAST(StartSession)DirectPlay3AImpl_StartSession,
3501   XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
3502   XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
3503   XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
3504   XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
3505
3506   DirectPlay4AImpl_GetGroupOwner,
3507   DirectPlay4AImpl_SetGroupOwner,
3508   DirectPlay4AImpl_SendEx,
3509   DirectPlay4AImpl_GetMessageQueue,
3510   DirectPlay4AImpl_CancelMessage,
3511   DirectPlay4AImpl_CancelPriority
3512 };
3513 #undef XCAST
3514
3515
3516 /***************************************************************************
3517  *  DirectPlayEnumerateA (DPLAYX.2) 
3518  *
3519  *  The pointer to the structure lpContext will be filled with the 
3520  *  appropriate data for each service offered by the OS. These services are
3521  *  not necessarily available on this particular machine but are defined
3522  *  as simple service providers under the "Service Providers" registry key.
3523  *  This structure is then passed to lpEnumCallback for each of the different 
3524  *  services. 
3525  *
3526  *  This API is useful only for applications written using DirectX3 or
3527  *  worse. It is superceeded by IDirectPlay3::EnumConnections which also
3528  *  gives information on the actual connections.
3529  *
3530  * defn of a service provider:
3531  * A dynamic-link library used by DirectPlay to communicate over a network. 
3532  * The service provider contains all the network-specific code required
3533  * to send and receive messages. Online services and network operators can
3534  * supply service providers to use specialized hardware, protocols, communications
3535  * media, and network resources. 
3536  *
3537  * TODO: Allocate string buffer space from the heap (length from reg)
3538  *       Pass real device driver numbers...
3539  *       Get the GUID properly...
3540  */
3541 HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
3542                                      LPVOID lpContext )
3543 {
3544
3545   HKEY   hkResult; 
3546   LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3547   DWORD  dwIndex;
3548   DWORD  sizeOfSubKeyName=50;
3549   char   subKeyName[51]; 
3550   FILETIME filetime;
3551
3552   TRACE(": lpEnumCallback=%p lpContext=%p\n", lpEnumCallback, lpContext );
3553
3554   if( !lpEnumCallback || !*lpEnumCallback )
3555   {
3556      return DPERR_INVALIDPARAMS;
3557   }
3558
3559   /* Need to loop over the service providers in the registry */
3560   if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3561                        0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3562   {
3563     /* Hmmm. Does this mean that there are no service providers? */ 
3564     ERR(": no service providers?\n");
3565     return DP_OK; 
3566   }
3567
3568   /* Traverse all the service providers we have available */
3569   for( dwIndex=0;
3570        RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName, 
3571                       NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3572        ++dwIndex, sizeOfSubKeyName=50 )
3573   {
3574     LPSTR    majVerDataSubKey = "dwReserved1";  
3575     LPSTR    minVerDataSubKey = "dwReserved2";  
3576     LPSTR    guidDataSubKey   = "Guid";
3577     HKEY     hkServiceProvider;
3578     GUID     serviceProviderGUID;
3579     DWORD    returnTypeGUID, returnTypeReserved, sizeOfReturnBuffer = 50;
3580     char     returnBuffer[51];
3581     DWORD    majVersionNum , minVersionNum = 0;
3582     LPWSTR   lpWGUIDString; 
3583
3584     TRACE(" this time through: %s\n", subKeyName );
3585
3586     /* Get a handle for this particular service provider */
3587     if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3588                          &hkServiceProvider ) != ERROR_SUCCESS )
3589     {
3590       ERR(": what the heck is going on?\n" );
3591       continue;
3592     }
3593
3594     /* Get the GUID, Device major number and device minor number 
3595      * from the registry. 
3596      */
3597     if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3598                             NULL, &returnTypeGUID, returnBuffer,
3599                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3600     {
3601       ERR(": missing GUID registry data members\n" );
3602       continue; 
3603     }
3604
3605     /* FIXME: Check return types to ensure we're interpreting data right */
3606     lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer );
3607     CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID ); 
3608     HeapFree( GetProcessHeap(), 0, lpWGUIDString );
3609
3610     /* FIXME: Need to know which of dwReserved1 and dwReserved2 are maj and min */
3611
3612     sizeOfReturnBuffer = 50;
3613     if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
3614                             NULL, &returnTypeReserved, returnBuffer,
3615                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3616     {
3617       ERR(": missing dwReserved1 registry data members\n") ;
3618       continue; 
3619     }
3620
3621     majVersionNum = GET_DWORD( returnBuffer );
3622
3623     sizeOfReturnBuffer = 50;
3624     if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
3625                             NULL, &returnTypeReserved, returnBuffer,
3626                             &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3627     {
3628       ERR(": missing dwReserved2 registry data members\n") ;
3629       continue;
3630     }
3631
3632     minVersionNum = GET_DWORD( returnBuffer );
3633
3634
3635     /* The enumeration will return FALSE if we are not to continue */
3636     if( !lpEnumCallback( &serviceProviderGUID , subKeyName,
3637                          majVersionNum, minVersionNum, lpContext ) )
3638     {
3639       WARN("lpEnumCallback returning FALSE\n" );
3640       break;
3641     }
3642   }
3643
3644   return DP_OK;
3645
3646 }
3647
3648 /***************************************************************************
3649  *  DirectPlayEnumerateW (DPLAYX.3)
3650  *
3651  */
3652 HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
3653 {
3654
3655   FIXME(":stub\n");
3656
3657   return DPERR_OUTOFMEMORY; 
3658
3659 }
3660
3661 /***************************************************************************
3662  *  DirectPlayCreate (DPLAYX.1) (DPLAY.1)
3663  *
3664  */
3665 HRESULT WINAPI DirectPlayCreate
3666 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
3667 {
3668   TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
3669
3670   if( pUnk != NULL )
3671   {
3672     return CLASS_E_NOAGGREGATION;
3673   }
3674
3675
3676   /* Create an IDirectPlay object. We don't support that so we'll cheat and
3677      give them an IDirectPlay2A object and hope that doesn't cause problems */
3678   if( directPlay_QueryInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
3679   {
3680     return DPERR_UNAVAILABLE;
3681   } 
3682
3683   if( IsEqualGUID( &GUID_NULL, lpGUID ) )
3684   {
3685     /* The GUID_NULL means don't bind a service provider. Just return the
3686        interface */ 
3687     return DP_OK;
3688   }
3689
3690
3691   /* Bind the desired service provider */
3692   if( ( IsEqualGUID( lpGUID, &DPSPGUID_MODEM ) ) ||
3693       ( IsEqualGUID( lpGUID, &DPSPGUID_SERIAL ) ) ||
3694       ( IsEqualGUID( lpGUID, &DPSPGUID_TCPIP ) ) ||
3695       ( IsEqualGUID( lpGUID, &DPSPGUID_IPX ) ) 
3696     )
3697   {
3698      FIXME( "Service provider binding not supported yet\n" );
3699      IDirectPlayX_Release( *lplpDP );
3700      *lplpDP = NULL;
3701      return DPERR_INVALIDPARAMS; 
3702   }
3703
3704   ERR( "unknown Service Provider %s\n", debugstr_guid(lpGUID) );
3705
3706   IDirectPlayX_Release( *lplpDP );
3707   *lplpDP = NULL;
3708
3709   return DPERR_INVALIDPARAMS;
3710 }