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