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