Make more of the OLE interface vtables const.
[wine] / dlls / dplayx / dplaysp.c
1 /* This contains the implementation of the interface Service
2  * Providers require to communicate with Direct Play
3  *
4  * Copyright 2000 Peter Hunnisett
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <string.h>
22 #include "winerror.h"
23 #include "wine/debug.h"
24
25 #include "dpinit.h"
26 #include "dplaysp.h"
27 #include "dplay_global.h"
28 #include "name_server.h"
29 #include "dplayx_messages.h"
30
31 #include "dplayx_global.h" /* FIXME: For global hack */
32
33 /* FIXME: Need to add interface locking inside procedures */
34
35 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
36
37 /* Prototypes */
38 static BOOL DPSP_CreateIUnknown( LPVOID lpSP );
39 static BOOL DPSP_DestroyIUnknown( LPVOID lpSP );
40 static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp );
41 static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP );
42
43 /* Predefine the interface */
44 typedef struct IDirectPlaySPImpl IDirectPlaySPImpl;
45
46 typedef struct tagDirectPlaySPIUnknownData
47 {
48   ULONG             ulObjRef;
49   CRITICAL_SECTION  DPSP_lock;
50 } DirectPlaySPIUnknownData;
51
52 typedef struct tagDirectPlaySPData
53 {
54   LPVOID lpSpRemoteData;
55   DWORD  dwSpRemoteDataSize; /* Size of data pointed to by lpSpRemoteData */
56
57   LPVOID lpSpLocalData;
58   DWORD  dwSpLocalDataSize; /* Size of data pointed to by lpSpLocalData */
59
60   IDirectPlay2Impl* dplay; /* FIXME: This should perhaps be iface not impl */
61
62 } DirectPlaySPData;
63
64 #define DPSP_IMPL_FIELDS \
65    ULONG ulInterfaceRef; \
66    DirectPlaySPIUnknownData* unk; \
67    DirectPlaySPData* sp;
68
69 struct IDirectPlaySPImpl
70 {
71   const IDirectPlaySPVtbl *lpVtbl;
72   DPSP_IMPL_FIELDS
73 };
74
75 /* Forward declaration of virtual tables */
76 static const IDirectPlaySPVtbl directPlaySPVT;
77
78 /* This structure is passed to the DP object for safe keeping */
79 typedef struct tagDP_SPPLAYERDATA
80 {
81   LPVOID lpPlayerLocalData;
82   DWORD  dwPlayerLocalDataSize;
83
84   LPVOID lpPlayerRemoteData;
85   DWORD  dwPlayerRemoteDataSize;
86 } DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA;
87
88 /* Create the SP interface */
89 extern
90 HRESULT DPSP_CreateInterface( REFIID riid, LPVOID* ppvObj, IDirectPlay2Impl* dp )
91 {
92   TRACE( " for %s\n", debugstr_guid( riid ) );
93
94   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
95                        sizeof( IDirectPlaySPImpl ) );
96
97   if( *ppvObj == NULL )
98   {
99     return DPERR_OUTOFMEMORY;
100   }
101
102   if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
103   {
104     IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj;
105     This->lpVtbl = &directPlaySPVT;
106   }
107   else
108   {
109     /* Unsupported interface */
110     HeapFree( GetProcessHeap(), 0, *ppvObj );
111     *ppvObj = NULL;
112
113     return E_NOINTERFACE;
114   }
115
116   /* Initialize it */
117   if( DPSP_CreateIUnknown( *ppvObj ) &&
118       DPSP_CreateDirectPlaySP( *ppvObj, dp )
119     )
120   {
121     IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj );
122     return S_OK;
123   }
124
125   /* Initialize failed, destroy it */
126   DPSP_DestroyDirectPlaySP( *ppvObj );
127   DPSP_DestroyIUnknown( *ppvObj );
128
129   HeapFree( GetProcessHeap(), 0, *ppvObj );
130   *ppvObj = NULL;
131
132   return DPERR_NOMEMORY;
133 }
134
135 static BOOL DPSP_CreateIUnknown( LPVOID lpSP )
136 {
137   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
138
139   This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
140
141   if ( This->unk == NULL )
142   {
143     return FALSE;
144   }
145
146   InitializeCriticalSection( &This->unk->DPSP_lock );
147
148   return TRUE;
149 }
150
151 static BOOL DPSP_DestroyIUnknown( LPVOID lpSP )
152 {
153   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
154
155   DeleteCriticalSection( &This->unk->DPSP_lock );
156   HeapFree( GetProcessHeap(), 0, This->unk );
157
158   return TRUE;
159 }
160
161
162 static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp )
163 {
164   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
165
166   This->sp = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->sp) ) );
167
168   if ( This->sp == NULL )
169   {
170     return FALSE;
171   }
172
173   This->sp->dplay = dp;
174
175   /* Normally we should be keeping a reference, but since only the dplay
176    * interface that created us can destroy us, we do not keep a reference
177    * to it (ie we'd be stuck with always having one reference to the dplay
178    * object, and hence us, around).
179    * NOTE: The dp object does reference count us.
180    *
181    * FIXME: This is a kludge to get around a problem where a queryinterface
182    *        is used to get a new interface and then is closed. We will then
183    *        reference garbage. However, with this we will never deallocate
184    *        the interface we store. The correct fix is to require all
185    *        DP internal interfaces to use the This->dp2 interface which
186    *        should be changed to This->dp
187    */
188   IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
189
190   return TRUE;
191 }
192
193 static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP )
194 {
195   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)lpSP;
196
197   /* Normally we should be keeping a reference, but since only the dplay
198    * interface that created us can destroy us, we do not keep a reference
199    * to it (ie we'd be stuck with always having one reference to the dplay
200    * object, and hence us, around).
201    * NOTE: The dp object does reference count us.
202    */
203   /*IDirectPlayX_Release( (LPDIRECTPLAY2)This->sp->dplay ); */
204
205   HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
206   HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
207
208   /* FIXME: Need to delete player queue */
209
210   HeapFree( GetProcessHeap(), 0, This->sp );
211   return TRUE;
212 }
213
214 /* Interface implementation */
215
216 static HRESULT WINAPI DPSP_QueryInterface
217 ( LPDIRECTPLAYSP iface,
218   REFIID riid,
219   LPVOID* ppvObj )
220 {
221   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
222   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
223
224   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
225                        sizeof( *This ) );
226
227   if( *ppvObj == NULL )
228   {
229     return DPERR_OUTOFMEMORY;
230   }
231
232   CopyMemory( *ppvObj, This, sizeof( *This )  );
233   (*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
234
235   if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
236   {
237     IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)*ppvObj;
238     This->lpVtbl = &directPlaySPVT;
239   }
240   else
241   {
242     /* Unsupported interface */
243     HeapFree( GetProcessHeap(), 0, *ppvObj );
244     *ppvObj = NULL;
245
246     return E_NOINTERFACE;
247   }
248
249   IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj );
250
251   return S_OK;
252 }
253
254 static ULONG WINAPI DPSP_AddRef
255 ( LPDIRECTPLAYSP iface )
256 {
257   ULONG ulInterfaceRefCount, ulObjRefCount;
258   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
259
260   ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
261   ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
262
263   TRACE( "ref count incremented to %lu:%lu for %p\n",
264          ulInterfaceRefCount, ulObjRefCount, This );
265
266   return ulObjRefCount;
267 }
268
269 static ULONG WINAPI DPSP_Release
270 ( LPDIRECTPLAYSP iface )
271 {
272   ULONG ulInterfaceRefCount, ulObjRefCount;
273   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
274
275   ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
276   ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
277
278   TRACE( "ref count decremented to %lu:%lu for %p\n",
279          ulInterfaceRefCount, ulObjRefCount, This );
280
281   /* Deallocate if this is the last reference to the object */
282   if( ulObjRefCount == 0 )
283   {
284      DPSP_DestroyDirectPlaySP( This );
285      DPSP_DestroyIUnknown( This );
286   }
287
288   if( ulInterfaceRefCount == 0 )
289   {
290     HeapFree( GetProcessHeap(), 0, This );
291   }
292
293   return ulInterfaceRefCount;
294 }
295
296 static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry
297 ( LPDIRECTPLAYSP iface,
298   LPCWSTR lpSection,
299   LPCWSTR lpKey,
300   LPCVOID lpData,
301   DWORD   dwDataSize,
302   DWORD   dwMaxEntries
303 )
304 {
305   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
306
307   /* Should be able to call the comctl32 undocumented MRU routines.
308      I suspect that the interface works appropriately */
309   FIXME( "(%p)->(%p,%p%p,0x%08lx,0x%08lx): stub\n",
310          This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries );
311
312   return DP_OK;
313 }
314
315 static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress
316 ( LPDIRECTPLAYSP iface,
317   REFGUID guidSP,
318   REFGUID guidDataType,
319   LPCVOID lpData,
320   DWORD   dwDataSize,
321   LPVOID  lpAddress,
322   LPDWORD lpdwAddressSize
323 )
324 {
325   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
326
327   FIXME( "(%p)->(%s,%s,%p,0x%08lx,%p,%p): stub\n",
328          This, debugstr_guid(guidSP), debugstr_guid(guidDataType),
329          lpData, dwDataSize, lpAddress, lpdwAddressSize );
330
331   return DP_OK;
332 }
333
334 static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress
335 ( LPDIRECTPLAYSP iface,
336   LPDPENUMADDRESSCALLBACK lpEnumAddressCallback,
337   LPCVOID lpAddress,
338   DWORD dwAddressSize,
339   LPVOID lpContext
340 )
341 {
342   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
343
344   TRACE( "(%p)->(%p,%p,0x%08lx,%p)\n",
345          This, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
346
347   DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );
348
349   return DP_OK;
350 }
351
352 static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries
353 ( LPDIRECTPLAYSP iface,
354   LPCWSTR lpSection,
355   LPCWSTR lpKey,
356   LPENUMMRUCALLBACK lpEnumMRUCallback,
357   LPVOID lpContext
358 )
359 {
360   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
361
362   /* Should be able to call the comctl32 undocumented MRU routines.
363      I suspect that the interface works appropriately */
364   FIXME( "(%p)->(%p,%p,%p,%p,): stub\n",
365          This, lpSection, lpKey, lpEnumMRUCallback, lpContext );
366
367   return DP_OK;
368 }
369
370 static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags
371 ( LPDIRECTPLAYSP iface,
372   DPID idPlayer,
373   LPDWORD lpdwPlayerFlags
374 )
375 {
376   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
377
378   FIXME( "(%p)->(0x%08lx,%p): stub\n",
379          This, idPlayer, lpdwPlayerFlags );
380
381   return DP_OK;
382 }
383
384 static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
385 ( LPDIRECTPLAYSP iface,
386   DPID idPlayer,
387   LPVOID* lplpData,
388   LPDWORD lpdwDataSize,
389   DWORD dwFlags
390 )
391 {
392   HRESULT hr;
393   LPDP_SPPLAYERDATA lpPlayerData;
394   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
395
396   TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n",
397          This, idPlayer, lplpData, lpdwDataSize, dwFlags );
398
399   hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData );
400
401   if( FAILED(hr) )
402   {
403     TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
404     return DPERR_INVALIDPLAYER;
405   }
406
407   /* What to do in the case where there is nothing set yet? */
408   if( dwFlags == DPSET_LOCAL )
409   {
410     HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
411     *lplpData     = lpPlayerData->lpPlayerLocalData;
412     *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
413   }
414   else if( dwFlags == DPSET_REMOTE )
415   {
416     HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
417     *lplpData     = lpPlayerData->lpPlayerRemoteData;
418     *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
419   }
420
421   if( *lplpData == NULL )
422   {
423     hr = DPERR_GENERIC;
424   }
425
426   return hr;
427 }
428
429 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
430 ( LPDIRECTPLAYSP iface,
431   LPVOID lpMessageBody,
432   DWORD  dwMessageBodySize,
433   LPVOID lpMessageHeader
434 )
435 {
436   LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
437   HRESULT hr = DPERR_GENERIC;
438   WORD wCommandId;
439   WORD wVersion;
440   DPSP_REPLYDATA data;
441
442   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
443
444   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
445          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
446
447   wCommandId = lpMsg->wCommandId;
448   wVersion   = lpMsg->wVersion;
449
450   TRACE( "Incoming message has envelope of 0x%08lx, %u, %u\n",
451          lpMsg->dwMagic, wCommandId, wVersion );
452
453   if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
454   {
455     ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
456     return DPERR_GENERIC;
457   }
458
459 #if 0
460   {
461     const LPDWORD lpcHeader = (LPDWORD)lpMessageHeader;
462
463     TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
464            lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] );
465    }
466 #endif
467
468   /* Pass everything else to Direct Play */
469   data.lpMessage     = NULL;
470   data.dwMessageSize = 0;
471
472   /* Pass this message to the dplay interface to handle */
473   hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
474                          lpMessageHeader, wCommandId, wVersion,
475                          &data.lpMessage, &data.dwMessageSize );
476
477   if( FAILED(hr) )
478   {
479     ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) );
480   }
481
482   /* Do we want a reply? */
483   if( data.lpMessage != NULL )
484   {
485     data.lpSPMessageHeader = lpMessageHeader;
486     data.idNameServer      = 0;
487     data.lpISP             = iface;
488
489     hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
490
491     if( FAILED(hr) )
492     {
493       ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
494     }
495   }
496
497   return hr;
498
499 #if 0
500   HRESULT hr = DP_OK;
501   HANDLE  hReceiveEvent = 0;
502   /* FIXME: Aquire some sort of interface lock */
503   /* FIXME: Need some sort of context for this callback. Need to determine
504    *        how this is actually done with the SP
505    */
506   /* FIXME: Who needs to delete the message when done? */
507   switch( lpMsg->dwType )
508   {
509     case DPSYS_CREATEPLAYERORGROUP:
510     {
511       LPDPMSG_CREATEPLAYERORGROUP msg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg;
512
513       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
514       {
515         hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId,
516                                  &msg->dpnName, 0, msg->lpData,
517                                  msg->dwDataSize, msg->dwFlags, ... );
518       }
519       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
520       {
521         /* Group in group situation? */
522         if( msg->dpIdParent == DPID_NOPARENT_GROUP )
523         {
524           hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId,
525                                   &msg->dpnName, 0, msg->lpData,
526                                   msg->dwDataSize, msg->dwFlags, ... );
527         }
528         else /* Group in Group */
529         {
530           hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent,
531                                          &msg->dpnName, 0, msg->lpData,
532                                          msg->dwDataSize, msg->dwFlags, ... );
533         }
534       }
535       else /* Hmmm? */
536       {
537         ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
538         return;
539       }
540
541       break;
542     }
543
544     case DPSYS_DESTROYPLAYERORGROUP:
545     {
546       LPDPMSG_DESTROYPLAYERORGROUP msg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
547
548       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
549       {
550         hr = DP_IF_DestroyPlayer( This, msg->dpId, ... );
551       }
552       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
553       {
554         hr = DP_IF_DestroyGroup( This, msg->dpId, ... );
555       }
556       else /* Hmmm? */
557       {
558         ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
559         return;
560       }
561
562       break;
563     }
564
565     case DPSYS_ADDPLAYERTOGROUP:
566     {
567       LPDPMSG_ADDPLAYERTOGROUP msg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
568
569       hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... );
570       break;
571     }
572
573     case DPSYS_DELETEPLAYERFROMGROUP:
574     {
575       LPDPMSG_DELETEPLAYERFROMGROUP msg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
576
577       hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer,
578                                         ... );
579
580       break;
581     }
582
583     case DPSYS_SESSIONLOST:
584     {
585       LPDPMSG_SESSIONLOST msg = (LPDPMSG_SESSIONLOST)lpMsg;
586
587       FIXME( "DPSYS_SESSIONLOST not handled\n" );
588
589       break;
590     }
591
592     case DPSYS_HOST:
593     {
594       LPDPMSG_HOST msg = (LPDPMSG_HOST)lpMsg;
595
596       FIXME( "DPSYS_HOST not handled\n" );
597
598       break;
599     }
600
601     case DPSYS_SETPLAYERORGROUPDATA:
602     {
603       LPDPMSG_SETPLAYERORGROUPDATA msg = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
604
605       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
606       {
607         hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize,                                  DPSET_REMOTE, ... );
608       }
609       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
610       {
611         hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize,
612                                  DPSET_REMOTE, ... );
613       }
614       else /* Hmmm? */
615       {
616         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
617         return;
618       }
619
620       break;
621     }
622
623     case DPSYS_SETPLAYERORGROUPNAME:
624     {
625       LPDPMSG_SETPLAYERORGROUPNAME msg = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
626
627       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
628       {
629         hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... );
630       }
631       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
632       {
633         hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... );
634       }
635       else /* Hmmm? */
636       {
637         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
638         return;
639       }
640
641       break;
642     }
643
644     case DPSYS_SETSESSIONDESC;
645     {
646       LPDPMSG_SETSESSIONDESC msg = (LPDPMSG_SETSESSIONDESC)lpMsg;
647
648       hr = DP_IF_SetSessionDesc( This, &msg->dpDesc );
649
650       break;
651     }
652
653     case DPSYS_ADDGROUPTOGROUP:
654     {
655       LPDPMSG_ADDGROUPTOGROUP msg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg;
656
657       hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup,
658                                   ... );
659
660       break;
661     }
662
663     case DPSYS_DELETEGROUPFROMGROUP:
664     {
665       LPDPMSG_DELETEGROUPFROMGROUP msg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg;
666
667       hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup,
668                                        msg->dpIdGroup, ... );
669
670       break;
671     }
672
673     case DPSYS_SECUREMESSAGE:
674     {
675       LPDPMSG_SECUREMESSAGE msg = (LPDPMSG_SECUREMESSAGE)lpMsg;
676
677       FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
678
679       break;
680     }
681
682     case DPSYS_STARTSESSION:
683     {
684       LPDPMSG_STARTSESSION msg = (LPDPMSG_STARTSESSION)lpMsg;
685
686       FIXME( "DPSYS_STARTSESSION not implemented\n" );
687
688       break;
689     }
690
691     case DPSYS_CHAT:
692     {
693       LPDPMSG_CHAT msg = (LPDPMSG_CHAT)lpMsg;
694
695       FIXME( "DPSYS_CHAT not implemeneted\n" );
696
697       break;
698     }
699
700     case DPSYS_SETGROUPOWNER:
701     {
702       LPDPMSG_SETGROUPOWNER msg = (LPDPMSG_SETGROUPOWNER)lpMsg;
703
704       FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
705
706       break;
707     }
708
709     case DPSYS_SENDCOMPLETE:
710     {
711       LPDPMSG_SENDCOMPLETE msg = (LPDPMSG_SENDCOMPLETE)lpMsg;
712
713       FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
714
715       break;
716     }
717
718     default:
719     {
720       /* NOTE: This should be a user defined type. There is nothing that we
721        *       need to do with it except queue it.
722        */
723       TRACE( "Received user message type(?) 0x%08lx through SP.\n",
724               lpMsg->dwType );
725       break;
726     }
727   }
728
729   FIXME( "Queue message in the receive queue. Need some context data!\n" );
730
731   if( FAILED(hr) )
732   {
733     ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType );
734   }
735   /* If a receive event was registered for this player, invoke it */
736   if( hReceiveEvent )
737   {
738     SetEvent( hReceiveEvent );
739   }
740 #endif
741 }
742
743 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
744 ( LPDIRECTPLAYSP iface,
745   DPID idPlayer,
746   LPVOID lpData,
747   DWORD dwDataSize,
748   DWORD dwFlags
749 )
750 {
751   HRESULT           hr;
752   LPDP_SPPLAYERDATA lpPlayerEntry;
753   LPVOID            lpPlayerData;
754
755   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
756
757 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
758   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n",
759          This, idPlayer, lpData, dwDataSize, dwFlags );
760
761   hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
762   if( FAILED(hr) )
763   {
764     /* Player must not exist */
765     return DPERR_INVALIDPLAYER;
766   }
767
768   lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
769   CopyMemory( lpPlayerData, lpData, dwDataSize );
770
771   if( dwFlags == DPSET_LOCAL )
772   {
773     lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
774     lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
775   }
776   else if( dwFlags == DPSET_REMOTE )
777   {
778     lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
779     lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
780   }
781
782   hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
783
784   return hr;
785 }
786
787 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
788 ( LPDIRECTPLAYSP iface,
789   LPCDPCOMPOUNDADDRESSELEMENT lpElements,
790   DWORD dwElementCount,
791   LPVOID lpAddress,
792   LPDWORD lpdwAddressSize
793 )
794 {
795   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
796
797   FIXME( "(%p)->(%p,0x%08lx,%p,%p): stub\n",
798          This, lpElements, dwElementCount, lpAddress, lpdwAddressSize );
799
800   return DP_OK;
801 }
802
803 static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
804 ( LPDIRECTPLAYSP iface,
805   LPVOID* lplpData,
806   LPDWORD lpdwDataSize,
807   DWORD dwFlags
808 )
809 {
810   HRESULT hr = DP_OK;
811   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
812
813 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
814   TRACE( "(%p)->(%p,%p,0x%08lx)\n",
815          This, lplpData, lpdwDataSize, dwFlags );
816
817 #if 0
818   /* This is what the documentation says... */
819   if( dwFlags != DPSET_REMOTE )
820   {
821     return DPERR_INVALIDPARAMS;
822   }
823 #else
824   /* ... but most service providers call this with 1 */
825   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
826    * thing?
827    */
828   if( dwFlags != DPSET_REMOTE )
829   {
830     TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
831   }
832 #endif
833
834   /* FIXME: What to do in the case where this isn't initialized yet? */
835
836   /* Yes, we're supposed to return a pointer to the memory we have stored! */
837   if( dwFlags == DPSET_REMOTE )
838   {
839     *lpdwDataSize = This->sp->dwSpRemoteDataSize;
840     *lplpData     = This->sp->lpSpRemoteData;
841
842     if( This->sp->lpSpRemoteData == NULL )
843     {
844       hr = DPERR_GENERIC;
845     }
846   }
847   else if( dwFlags == DPSET_LOCAL )
848   {
849     *lpdwDataSize = This->sp->dwSpLocalDataSize;
850     *lplpData     = This->sp->lpSpLocalData;
851
852     if( This->sp->lpSpLocalData == NULL )
853     {
854       hr = DPERR_GENERIC;
855     }
856   }
857
858   return hr;
859 }
860
861 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
862 ( LPDIRECTPLAYSP iface,
863   LPVOID lpData,
864   DWORD dwDataSize,
865   DWORD dwFlags
866 )
867 {
868   LPVOID lpSpData;
869
870   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
871
872 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
873   TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n",
874          This, lpData, dwDataSize, dwFlags );
875
876 #if 0
877   /* This is what the documentation says... */
878   if( dwFlags != DPSET_REMOTE )
879   {
880     return DPERR_INVALIDPARAMS;
881   }
882 #else
883   /* ... but most service providers call this with 1 */
884   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
885    * thing?
886    */
887   if( dwFlags != DPSET_REMOTE )
888   {
889     TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
890   }
891 #endif
892
893   lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
894   CopyMemory( lpSpData, lpData, dwDataSize );
895
896   /* If we have data already allocated, free it and replace it */
897   if( dwFlags == DPSET_REMOTE )
898   {
899     HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
900     This->sp->dwSpRemoteDataSize = dwDataSize;
901     This->sp->lpSpRemoteData = lpSpData;
902   }
903   else if ( dwFlags == DPSET_LOCAL )
904   {
905     HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
906     This->sp->lpSpLocalData     = lpSpData;
907     This->sp->dwSpLocalDataSize = dwDataSize;
908   }
909
910   return DP_OK;
911 }
912
913 static VOID WINAPI IDirectPlaySPImpl_SendComplete
914 ( LPDIRECTPLAYSP iface,
915   LPVOID unknownA,
916   DWORD unknownB
917 )
918 {
919   IDirectPlaySPImpl *This = (IDirectPlaySPImpl *)iface;
920
921   FIXME( "(%p)->(%p,0x%08lx): stub\n",
922          This, unknownA, unknownB );
923 }
924
925 static const IDirectPlaySPVtbl directPlaySPVT =
926 {
927
928   DPSP_QueryInterface,
929   DPSP_AddRef,
930   DPSP_Release,
931
932   IDirectPlaySPImpl_AddMRUEntry,
933   IDirectPlaySPImpl_CreateAddress,
934   IDirectPlaySPImpl_EnumAddress,
935   IDirectPlaySPImpl_EnumMRUEntries,
936   IDirectPlaySPImpl_GetPlayerFlags,
937   IDirectPlaySPImpl_GetSPPlayerData,
938   IDirectPlaySPImpl_HandleMessage,
939   IDirectPlaySPImpl_SetSPPlayerData,
940   IDirectPlaySPImpl_CreateCompoundAddress,
941   IDirectPlaySPImpl_GetSPData,
942   IDirectPlaySPImpl_SetSPData,
943   IDirectPlaySPImpl_SendComplete
944 };
945
946
947 /* DP external interfaces to call into DPSP interface */
948
949 /* Allocate the structure */
950 extern LPVOID DPSP_CreateSPPlayerData(void)
951 {
952   TRACE( "Creating SPPlayer data struct\n" );
953   return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
954                     sizeof( DP_SPPLAYERDATA ) );
955 }