Moved standard syslevel APIs declaration to winbase.h.
[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 "heap.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   /* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */
172
173   /* FIXME: This is a kludge to get around a problem where a queryinterface
174    *        is used to get a new interface and then is closed. We will then
175    *        reference garbage. However, with this we will never deallocate
176    *        the interface we store. The correct fix is to require all 
177    *        DP internal interfaces to use the This->dp2 interface which
178    *        should be changed to This->dp
179    */
180   IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
181
182   return TRUE;
183 }
184
185 static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP )
186 {
187   ICOM_THIS(IDirectPlaySPImpl,lpSP);
188
189   /* Normally we should be keeping a reference, but since only the dplay
190    * interface that created us can destroy us, we do not keep a reference
191    * to it (ie we'd be stuck with always having one reference to the dplay
192    * object, and hence us, around).
193    * NOTE: The dp object does reference count us.
194    */
195   /*IDirectPlayX_Release( (LPDIRECTPLAY2)This->sp->dplay ); */
196
197   HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
198   HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
199
200   /* FIXME: Need to delete player queue */
201
202   HeapFree( GetProcessHeap(), 0, This->sp );
203   return TRUE;
204 }
205
206 /* Interface implementation */
207
208 static HRESULT WINAPI DPSP_QueryInterface
209 ( LPDIRECTPLAYSP iface,
210   REFIID riid,
211   LPVOID* ppvObj )
212 {
213   ICOM_THIS(IDirectPlaySPImpl,iface);
214   TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
215
216   *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
217                        sizeof( *This ) );
218
219   if( *ppvObj == NULL )
220   {
221     return DPERR_OUTOFMEMORY;
222   }
223
224   CopyMemory( *ppvObj, This, sizeof( *This )  );
225   (*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
226
227   if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
228   {
229     ICOM_THIS(IDirectPlaySPImpl,*ppvObj);
230     ICOM_VTBL(This) = &directPlaySPVT;
231   }
232   else
233   {
234     /* Unsupported interface */
235     HeapFree( GetProcessHeap(), 0, *ppvObj );
236     *ppvObj = NULL;
237
238     return E_NOINTERFACE;
239   }
240  
241   IDirectPlaySP_AddRef( (LPDIRECTPLAYSP)*ppvObj );
242
243   return S_OK;
244
245
246 static ULONG WINAPI DPSP_AddRef
247 ( LPDIRECTPLAYSP iface )
248 {
249   ULONG ulInterfaceRefCount, ulObjRefCount;
250   ICOM_THIS(IDirectPlaySPImpl,iface);
251
252   ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
253   ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
254
255   TRACE( "ref count incremented to %lu:%lu for %p\n",
256          ulInterfaceRefCount, ulObjRefCount, This );
257
258   return ulObjRefCount;
259 }
260
261 static ULONG WINAPI DPSP_Release
262 ( LPDIRECTPLAYSP iface )
263 {
264   ULONG ulInterfaceRefCount, ulObjRefCount;
265   ICOM_THIS(IDirectPlaySPImpl,iface);
266
267   ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
268   ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
269
270   TRACE( "ref count decremented to %lu:%lu for %p\n",
271          ulInterfaceRefCount, ulObjRefCount, This );
272
273   /* Deallocate if this is the last reference to the object */
274   if( ulObjRefCount == 0 )
275   {
276      DPSP_DestroyDirectPlaySP( This );
277      DPSP_DestroyIUnknown( This );
278   }
279
280   if( ulInterfaceRefCount == 0 )
281   {
282     HeapFree( GetProcessHeap(), 0, This );
283   }
284
285   return ulInterfaceRefCount;
286 }
287
288 static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry
289 ( LPDIRECTPLAYSP iface,
290   LPCWSTR lpSection,
291   LPCWSTR lpKey,
292   LPCVOID lpData, 
293   DWORD   dwDataSize, 
294   DWORD   dwMaxEntries
295 )
296 {
297   ICOM_THIS(IDirectPlaySPImpl,iface);
298
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   FIXME( "(%p)->(%p,%p,%p,%p,): stub\n", 
353          This, lpSection, lpKey, lpEnumMRUCallback, lpContext );
354
355   return DP_OK;
356 }
357
358 static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags
359 ( LPDIRECTPLAYSP iface,
360   DPID idPlayer, 
361   LPDWORD lpdwPlayerFlags
362 )
363 {
364   ICOM_THIS(IDirectPlaySPImpl,iface);
365
366   FIXME( "(%p)->(0x%08lx,%p): stub\n", 
367          This, idPlayer, lpdwPlayerFlags );
368
369   return DP_OK;
370 }
371
372 static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
373 ( LPDIRECTPLAYSP iface,
374   DPID idPlayer, 
375   LPVOID* lplpData, 
376   LPDWORD lpdwDataSize, 
377   DWORD dwFlags
378 )
379 {
380   HRESULT hr;
381   LPDP_SPPLAYERDATA lpPlayerData;
382   ICOM_THIS(IDirectPlaySPImpl,iface);
383
384 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
385   TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n", 
386          This, idPlayer, lplpData, lpdwDataSize, dwFlags );
387
388   hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData );
389
390   if( FAILED(hr) )
391   {
392     TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
393     return DPERR_INVALIDPLAYER;
394   }
395
396   /* What to do in the case where there is nothing set yet? */
397   if( dwFlags == DPSET_LOCAL )
398   {
399     if( lpPlayerData->lpPlayerLocalData )
400     {
401       HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
402     }
403
404     *lplpData     = lpPlayerData->lpPlayerLocalData;
405     *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
406   }
407   else if( dwFlags == DPSET_REMOTE )
408   {
409     if( lpPlayerData->lpPlayerRemoteData )
410     {
411       HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
412     }
413
414     *lplpData     = lpPlayerData->lpPlayerRemoteData;
415     *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
416   }
417
418   if( *lplpData == NULL )
419   {
420     hr = DPERR_GENERIC;
421   } 
422
423   return hr;
424 }
425
426 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
427 ( LPDIRECTPLAYSP iface,
428   LPVOID lpMessageBody, 
429   DWORD  dwMessageBodySize, 
430   LPVOID lpMessageHeader
431 )
432 {
433   LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
434   HRESULT hr = DPERR_GENERIC;
435   WORD wCommandId;
436   WORD wVersion;
437
438   ICOM_THIS(IDirectPlaySPImpl,iface);
439
440 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
441   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n", 
442          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
443
444   wCommandId = lpMsg->wCommandId;
445   wVersion   = lpMsg->wVersion;
446
447   TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n", 
448          lpMsg->dwMagic, wCommandId, wVersion );
449
450   if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
451   {
452     ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
453   }
454
455   switch( lpMsg->wCommandId )
456   {
457     /* Name server needs to handle this request */
458     /* FIXME: This should be done in direct play handler */
459     case DPMSGCMD_ENUMSESSIONSREQUEST:
460     {
461       DPSP_REPLYDATA data;
462
463       data.lpSPMessageHeader = lpMessageHeader;
464       data.idNameServer      = 0;
465       data.lpISP             = iface;
466  
467       NS_ReplyToEnumSessionsRequest( lpMessageBody, &data, This->sp->dplay );
468
469       hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
470
471       if( FAILED(hr) )
472       {
473         ERR( "Reply failed 0x%08lx\n", hr );
474       }
475
476       break;
477     }
478
479     /* Name server needs to handle this request */
480     /* FIXME: This should be done in direct play handler */
481     case DPMSGCMD_ENUMSESSIONSREPLY:
482     {
483       NS_SetRemoteComputerAsNameServer( lpMessageHeader, 
484                                         This->sp->dplay->dp2->spData.dwSPHeaderSize,
485                                         (LPDPMSG_ENUMSESSIONSREPLY)lpMessageBody,
486                                         This->sp->dplay->dp2->lpNameServerData );
487
488       /* No reply expected */
489       hr = DP_OK;
490
491       break;
492     }
493
494     /* Pass everything else to Direct Play */
495     default:
496     {
497       DPSP_REPLYDATA data;
498       
499       data.lpMessage     = NULL;
500       data.dwMessageSize = 0;
501
502       /* Pass this message to the dplay interface to handle */
503       hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
504                              lpMessageHeader, wCommandId, wVersion, 
505                              &data.lpMessage, &data.dwMessageSize );
506
507       /* Do we want a reply? */
508       if( data.lpMessage != NULL )
509       {
510         HRESULT hr;
511
512         data.lpSPMessageHeader = lpMessageHeader;
513         data.idNameServer      = 0;
514         data.lpISP             = iface;
515
516         hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
517
518         if( FAILED(hr) )
519         {
520           ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
521         }
522       }
523
524       break;
525     }
526   }
527
528 #if 0
529   HRESULT hr = DP_OK;
530   HANDLE  hReceiveEvent = 0;
531   /* FIXME: Aquire some sort of interface lock */
532   /* FIXME: Need some sort of context for this callback. Need to determine
533    *        how this is actually done with the SP
534    */
535   /* FIXME: Who needs to delete the message when done? */
536   switch( lpMsg->dwType )
537   {
538     case DPSYS_CREATEPLAYERORGROUP:
539     {
540       LPDPMSG_CREATEPLAYERORGROUP msg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg;
541
542       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
543       {
544         hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId, 
545                                  &msg->dpnName, 0, msg->lpData, 
546                                  msg->dwDataSize, msg->dwFlags, ... );
547       }
548       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
549       {
550         /* Group in group situation? */
551         if( msg->dpIdParent == DPID_NOPARENT_GROUP )
552         {
553           hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId, 
554                                   &msg->dpnName, 0, msg->lpData, 
555                                   msg->dwDataSize, msg->dwFlags, ... );
556         }
557         else /* Group in Group */
558         {
559           hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent,
560                                          &msg->dpnName, 0, msg->lpData, 
561                                          msg->dwDataSize, msg->dwFlags, ... );
562         }
563       }
564       else /* Hmmm? */
565       {
566         ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
567         return;
568       }
569
570       break;
571     }
572
573     case DPSYS_DESTROYPLAYERORGROUP:
574     {
575       LPDPMSG_DESTROYPLAYERORGROUP msg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
576
577       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
578       {
579         hr = DP_IF_DestroyPlayer( This, msg->dpId, ... );
580       }
581       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
582       {
583         hr = DP_IF_DestroyGroup( This, msg->dpId, ... );
584       }
585       else /* Hmmm? */
586       {
587         ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
588         return;
589       }
590
591       break;
592     }
593
594     case DPSYS_ADDPLAYERTOGROUP:
595     {
596       LPDPMSG_ADDPLAYERTOGROUP msg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
597
598       hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... );
599       break;
600     }
601
602     case DPSYS_DELETEPLAYERFROMGROUP:
603     {
604       LPDPMSG_DELETEPLAYERFROMGROUP msg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
605
606       hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer,
607                                         ... );
608
609       break;
610     }
611
612     case DPSYS_SESSIONLOST:
613     {
614       LPDPMSG_SESSIONLOST msg = (LPDPMSG_SESSIONLOST)lpMsg;
615
616       FIXME( "DPSYS_SESSIONLOST not handled\n" );
617
618       break;
619     }
620
621     case DPSYS_HOST:
622     {
623       LPDPMSG_HOST msg = (LPDPMSG_HOST)lpMsg;
624
625       FIXME( "DPSYS_HOST not handled\n" );
626
627       break;
628     }
629
630     case DPSYS_SETPLAYERORGROUPDATA:
631     {
632       LPDPMSG_SETPLAYERORGROUPDATA msg = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
633
634       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
635       {
636         hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize,                                  DPSET_REMOTE, ... );
637       }
638       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
639       {
640         hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize,
641                                  DPSET_REMOTE, ... );
642       }
643       else /* Hmmm? */
644       {
645         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
646         return;
647       }
648
649       break;
650     }
651
652     case DPSYS_SETPLAYERORGROUPNAME:
653     {
654       LPDPMSG_SETPLAYERORGROUPNAME msg = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
655
656       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
657       {
658         hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... );
659       }
660       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
661       {
662         hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... );
663       }
664       else /* Hmmm? */
665       {
666         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
667         return;
668       }
669
670       break;
671     }
672
673     case DPSYS_SETSESSIONDESC;
674     {
675       LPDPMSG_SETSESSIONDESC msg = (LPDPMSG_SETSESSIONDESC)lpMsg;
676
677       hr = DP_IF_SetSessionDesc( This, &msg->dpDesc );
678
679       break;
680     }
681
682     case DPSYS_ADDGROUPTOGROUP:
683     {
684       LPDPMSG_ADDGROUPTOGROUP msg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg;
685
686       hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup,
687                                   ... );
688
689       break;
690     }
691
692     case DPSYS_DELETEGROUPFROMGROUP:
693     {
694       LPDPMSG_DELETEGROUPFROMGROUP msg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg;
695
696       hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup,
697                                        msg->dpIdGroup, ... );
698
699       break;
700     }
701
702     case DPSYS_SECUREMESSAGE:
703     {
704       LPDPMSG_SECUREMESSAGE msg = (LPDPMSG_SECUREMESSAGE)lpMsg;
705
706       FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
707
708       break;
709     }
710
711     case DPSYS_STARTSESSION:
712     {
713       LPDPMSG_STARTSESSION msg = (LPDPMSG_STARTSESSION)lpMsg;
714
715       FIXME( "DPSYS_STARTSESSION not implemented\n" );
716
717       break;
718     }
719
720     case DPSYS_CHAT:
721     {
722       LPDPMSG_CHAT msg = (LPDPMSG_CHAT)lpMsg;
723
724       FIXME( "DPSYS_CHAT not implemeneted\n" );
725
726       break;
727     }   
728
729     case DPSYS_SETGROUPOWNER:
730     {
731       LPDPMSG_SETGROUPOWNER msg = (LPDPMSG_SETGROUPOWNER)lpMsg;
732
733       FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
734
735       break;
736     }
737
738     case DPSYS_SENDCOMPLETE:
739     {
740       LPDPMSG_SENDCOMPLETE msg = (LPDPMSG_SENDCOMPLETE)lpMsg;
741
742       FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
743
744       break;
745     }
746
747     default:
748     {
749       /* NOTE: This should be a user defined type. There is nothing that we
750        *       need to do with it except queue it.
751        */
752       TRACE( "Received user message type(?) 0x%08lx through SP.\n",
753               lpMsg->dwType );
754       break;
755     }
756   }
757
758   FIXME( "Queue message in the receive queue. Need some context data!\n" );
759
760   if( FAILED(hr) )
761   {
762     ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType );
763   }
764   /* If a receieve event was registered for this player, invoke it */
765   if( hReceiveEvent )
766   {
767     SetEvent( hReceiveEvent );
768   }
769 #endif
770
771   return hr;
772 }
773
774 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
775 ( LPDIRECTPLAYSP iface,
776   DPID idPlayer, 
777   LPVOID lpData, 
778   DWORD dwDataSize, 
779   DWORD dwFlags
780 )
781 {
782   HRESULT           hr;
783   LPDP_SPPLAYERDATA lpPlayerEntry;
784   LPVOID            lpPlayerData; 
785
786   ICOM_THIS(IDirectPlaySPImpl,iface);
787
788 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
789   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n", 
790          This, idPlayer, lpData, dwDataSize, dwFlags );
791
792   hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
793   if( FAILED(hr) )
794   {
795     /* Player must not exist */
796     return DPERR_INVALIDPLAYER;
797   }
798
799   lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
800   CopyMemory( lpPlayerData, lpData, dwDataSize );
801
802   if( dwFlags == DPSET_LOCAL )
803   {
804     lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
805     lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
806   }
807   else if( dwFlags == DPSET_REMOTE )
808   {
809     lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
810     lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
811   }
812
813   hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
814
815   return hr;
816 }
817
818 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
819 ( LPDIRECTPLAYSP iface,
820   LPCDPCOMPOUNDADDRESSELEMENT lpElements, 
821   DWORD dwElementCount, 
822   LPVOID lpAddress, 
823   LPDWORD lpdwAddressSize
824 )
825 {
826   ICOM_THIS(IDirectPlaySPImpl,iface);
827
828   FIXME( "(%p)->(%p,0x%08lx,%p,%p): stub\n", 
829          This, lpElements, dwElementCount, lpAddress, lpdwAddressSize );
830
831   return DP_OK;
832 }
833
834 static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
835 ( LPDIRECTPLAYSP iface,
836   LPVOID* lplpData, 
837   LPDWORD lpdwDataSize, 
838   DWORD dwFlags
839 )
840 {
841   HRESULT hr = DP_OK;
842   ICOM_THIS(IDirectPlaySPImpl,iface);
843
844 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
845   TRACE( "(%p)->(%p,%p,0x%08lx)\n", 
846          This, lplpData, lpdwDataSize, dwFlags );
847
848 #if 0
849   /* This is what the documentation says... */
850   if( dwFlags != DPSET_REMOTE )
851   {
852     return DPERR_INVALIDPARAMS;
853   }
854 #else
855   /* ... but most service providers call this with 1 */
856   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
857    * thing?
858    */
859   if( dwFlags != DPSET_REMOTE )
860   {
861     FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
862   }
863 #endif
864
865   /* FIXME: What to do in the case where this isn't initialized yet? */
866
867   /* Yes, we're supposed to return a pointer to the memory we have stored! */
868   if( dwFlags == DPSET_REMOTE )
869   {
870     *lpdwDataSize = This->sp->dwSpRemoteDataSize;
871     *lplpData     = This->sp->lpSpRemoteData;
872
873     if( This->sp->lpSpRemoteData == NULL )
874     {
875       hr = DPERR_GENERIC;
876     }
877   }
878   else if( dwFlags == DPSET_LOCAL )
879   {
880     *lpdwDataSize = This->sp->dwSpLocalDataSize;
881     *lplpData     = This->sp->lpSpLocalData;
882
883     if( This->sp->lpSpLocalData == NULL )
884     {
885       hr = DPERR_GENERIC;
886     }
887   }
888
889   return hr;
890 }
891
892 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
893 ( LPDIRECTPLAYSP iface,
894   LPVOID lpData, 
895   DWORD dwDataSize, 
896   DWORD dwFlags
897 )
898 {
899   LPVOID lpSpData;
900
901   ICOM_THIS(IDirectPlaySPImpl,iface);
902
903 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
904   TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n", 
905          This, lpData, dwDataSize, dwFlags );
906
907 #if 0
908   /* This is what the documentation says... */
909   if( dwFlags != DPSET_REMOTE )
910   {
911     return DPERR_INVALIDPARAMS;
912   }
913 #else
914   /* ... but most service providers call this with 1 */
915   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
916    * thing?
917    */
918   if( dwFlags != DPSET_REMOTE )
919   {
920     FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
921   }
922 #endif
923
924   lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
925   CopyMemory( lpSpData, lpData, dwDataSize );
926
927   /* If we have data already allocated, free it and replace it */
928   if( dwFlags == DPSET_REMOTE )
929   {
930     if( This->sp->lpSpRemoteData )
931     {
932       HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
933     }
934
935     This->sp->dwSpRemoteDataSize = dwDataSize;
936     This->sp->lpSpRemoteData = lpSpData;
937   }
938   else if ( dwFlags == DPSET_LOCAL )
939   {
940     if( This->sp->lpSpLocalData )
941     {
942       HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
943     }
944
945     This->sp->lpSpLocalData     = lpSpData;
946     This->sp->dwSpLocalDataSize = dwDataSize;
947   }
948
949   return DP_OK;
950 }
951
952 static VOID WINAPI IDirectPlaySPImpl_SendComplete
953 ( LPDIRECTPLAYSP iface,
954   LPVOID unknownA, 
955   DWORD unknownB
956 )
957 {
958   ICOM_THIS(IDirectPlaySPImpl,iface);
959
960   FIXME( "(%p)->(%p,0x%08lx): stub\n", 
961          This, unknownA, unknownB );
962 }
963
964
965 static struct ICOM_VTABLE(IDirectPlaySP) directPlaySPVT =
966 {
967   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
968
969   DPSP_QueryInterface,
970   DPSP_AddRef,
971   DPSP_Release,
972
973   IDirectPlaySPImpl_AddMRUEntry,
974   IDirectPlaySPImpl_CreateAddress,
975   IDirectPlaySPImpl_EnumAddress,
976   IDirectPlaySPImpl_EnumMRUEntries,
977   IDirectPlaySPImpl_GetPlayerFlags,
978   IDirectPlaySPImpl_GetSPPlayerData,
979   IDirectPlaySPImpl_HandleMessage,
980   IDirectPlaySPImpl_SetSPPlayerData,
981   IDirectPlaySPImpl_CreateCompoundAddress,
982   IDirectPlaySPImpl_GetSPData,
983   IDirectPlaySPImpl_SetSPData,
984   IDirectPlaySPImpl_SendComplete
985 };
986
987
988 /* DP external interfaces to call into DPSP interface */
989
990 /* Allocate the structure */
991 extern LPVOID DPSP_CreateSPPlayerData(void)
992 {
993   TRACE( "Creating SPPlayer data struct\n" );
994   return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
995                     sizeof( DP_SPPLAYERDATA ) );
996 }
997