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