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