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