Made the dll entry point default to DllMain and removed most of the
[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  * 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   ICOM_VFIELD(IDirectPlaySP);
72   DPSP_IMPL_FIELDS
73 };
74
75 /* Forward declaration of virtual tables */
76 static ICOM_VTABLE(IDirectPlaySP) 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     ICOM_THIS(IDirectPlaySPImpl,*ppvObj);
105     ICOM_VTBL(This) = &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   ICOM_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   ICOM_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   ICOM_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   ICOM_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   ICOM_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     ICOM_THIS(IDirectPlaySPImpl,*ppvObj);
242     ICOM_VTBL(This) = &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   ICOM_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   ICOM_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   ICOM_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   ICOM_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   ICOM_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   ICOM_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   ICOM_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   ICOM_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     if( lpPlayerData->lpPlayerLocalData )
415     {
416       HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
417     }
418
419     *lplpData     = lpPlayerData->lpPlayerLocalData;
420     *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
421   }
422   else if( dwFlags == DPSET_REMOTE )
423   {
424     if( lpPlayerData->lpPlayerRemoteData )
425     {
426       HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
427     }
428
429     *lplpData     = lpPlayerData->lpPlayerRemoteData;
430     *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
431   }
432
433   if( *lplpData == NULL )
434   {
435     hr = DPERR_GENERIC;
436   }
437
438   return hr;
439 }
440
441 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
442 ( LPDIRECTPLAYSP iface,
443   LPVOID lpMessageBody,
444   DWORD  dwMessageBodySize,
445   LPVOID lpMessageHeader
446 )
447 {
448   LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
449   HRESULT hr = DPERR_GENERIC;
450   WORD wCommandId;
451   WORD wVersion;
452   DPSP_REPLYDATA data;
453
454   ICOM_THIS(IDirectPlaySPImpl,iface);
455
456   FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
457          This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
458
459   wCommandId = lpMsg->wCommandId;
460   wVersion   = lpMsg->wVersion;
461
462   TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n",
463          lpMsg->dwMagic, wCommandId, wVersion );
464
465   if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
466   {
467     ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
468     return DPERR_GENERIC;
469   }
470
471 #if 0
472   {
473     const LPDWORD lpcHeader = (LPDWORD)lpMessageHeader;
474
475     TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
476            lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] );
477    }
478 #endif
479
480   /* Pass everything else to Direct Play */
481   data.lpMessage     = NULL;
482   data.dwMessageSize = 0;
483
484   /* Pass this message to the dplay interface to handle */
485   hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
486                          lpMessageHeader, wCommandId, wVersion,
487                          &data.lpMessage, &data.dwMessageSize );
488
489   if( FAILED(hr) )
490   {
491     ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) );
492   }
493
494   /* Do we want a reply? */
495   if( data.lpMessage != NULL )
496   {
497     data.lpSPMessageHeader = lpMessageHeader;
498     data.idNameServer      = 0;
499     data.lpISP             = iface;
500
501     hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
502
503     if( FAILED(hr) )
504     {
505       ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
506     }
507   }
508
509   return hr;
510
511 #if 0
512   HRESULT hr = DP_OK;
513   HANDLE  hReceiveEvent = 0;
514   /* FIXME: Aquire some sort of interface lock */
515   /* FIXME: Need some sort of context for this callback. Need to determine
516    *        how this is actually done with the SP
517    */
518   /* FIXME: Who needs to delete the message when done? */
519   switch( lpMsg->dwType )
520   {
521     case DPSYS_CREATEPLAYERORGROUP:
522     {
523       LPDPMSG_CREATEPLAYERORGROUP msg = (LPDPMSG_CREATEPLAYERORGROUP)lpMsg;
524
525       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
526       {
527         hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId,
528                                  &msg->dpnName, 0, msg->lpData,
529                                  msg->dwDataSize, msg->dwFlags, ... );
530       }
531       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
532       {
533         /* Group in group situation? */
534         if( msg->dpIdParent == DPID_NOPARENT_GROUP )
535         {
536           hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId,
537                                   &msg->dpnName, 0, msg->lpData,
538                                   msg->dwDataSize, msg->dwFlags, ... );
539         }
540         else /* Group in Group */
541         {
542           hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent,
543                                          &msg->dpnName, 0, msg->lpData,
544                                          msg->dwDataSize, msg->dwFlags, ... );
545         }
546       }
547       else /* Hmmm? */
548       {
549         ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
550         return;
551       }
552
553       break;
554     }
555
556     case DPSYS_DESTROYPLAYERORGROUP:
557     {
558       LPDPMSG_DESTROYPLAYERORGROUP msg = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
559
560       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
561       {
562         hr = DP_IF_DestroyPlayer( This, msg->dpId, ... );
563       }
564       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
565       {
566         hr = DP_IF_DestroyGroup( This, msg->dpId, ... );
567       }
568       else /* Hmmm? */
569       {
570         ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
571         return;
572       }
573
574       break;
575     }
576
577     case DPSYS_ADDPLAYERTOGROUP:
578     {
579       LPDPMSG_ADDPLAYERTOGROUP msg = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
580
581       hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... );
582       break;
583     }
584
585     case DPSYS_DELETEPLAYERFROMGROUP:
586     {
587       LPDPMSG_DELETEPLAYERFROMGROUP msg = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
588
589       hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer,
590                                         ... );
591
592       break;
593     }
594
595     case DPSYS_SESSIONLOST:
596     {
597       LPDPMSG_SESSIONLOST msg = (LPDPMSG_SESSIONLOST)lpMsg;
598
599       FIXME( "DPSYS_SESSIONLOST not handled\n" );
600
601       break;
602     }
603
604     case DPSYS_HOST:
605     {
606       LPDPMSG_HOST msg = (LPDPMSG_HOST)lpMsg;
607
608       FIXME( "DPSYS_HOST not handled\n" );
609
610       break;
611     }
612
613     case DPSYS_SETPLAYERORGROUPDATA:
614     {
615       LPDPMSG_SETPLAYERORGROUPDATA msg = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
616
617       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
618       {
619         hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize,                                  DPSET_REMOTE, ... );
620       }
621       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
622       {
623         hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize,
624                                  DPSET_REMOTE, ... );
625       }
626       else /* Hmmm? */
627       {
628         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
629         return;
630       }
631
632       break;
633     }
634
635     case DPSYS_SETPLAYERORGROUPNAME:
636     {
637       LPDPMSG_SETPLAYERORGROUPNAME msg = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
638
639       if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
640       {
641         hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... );
642       }
643       else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
644       {
645         hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... );
646       }
647       else /* Hmmm? */
648       {
649         ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
650         return;
651       }
652
653       break;
654     }
655
656     case DPSYS_SETSESSIONDESC;
657     {
658       LPDPMSG_SETSESSIONDESC msg = (LPDPMSG_SETSESSIONDESC)lpMsg;
659
660       hr = DP_IF_SetSessionDesc( This, &msg->dpDesc );
661
662       break;
663     }
664
665     case DPSYS_ADDGROUPTOGROUP:
666     {
667       LPDPMSG_ADDGROUPTOGROUP msg = (LPDPMSG_ADDGROUPTOGROUP)lpMsg;
668
669       hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup,
670                                   ... );
671
672       break;
673     }
674
675     case DPSYS_DELETEGROUPFROMGROUP:
676     {
677       LPDPMSG_DELETEGROUPFROMGROUP msg = (LPDPMSG_DELETEGROUPFROMGROUP)lpMsg;
678
679       hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup,
680                                        msg->dpIdGroup, ... );
681
682       break;
683     }
684
685     case DPSYS_SECUREMESSAGE:
686     {
687       LPDPMSG_SECUREMESSAGE msg = (LPDPMSG_SECUREMESSAGE)lpMsg;
688
689       FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
690
691       break;
692     }
693
694     case DPSYS_STARTSESSION:
695     {
696       LPDPMSG_STARTSESSION msg = (LPDPMSG_STARTSESSION)lpMsg;
697
698       FIXME( "DPSYS_STARTSESSION not implemented\n" );
699
700       break;
701     }
702
703     case DPSYS_CHAT:
704     {
705       LPDPMSG_CHAT msg = (LPDPMSG_CHAT)lpMsg;
706
707       FIXME( "DPSYS_CHAT not implemeneted\n" );
708
709       break;
710     }
711
712     case DPSYS_SETGROUPOWNER:
713     {
714       LPDPMSG_SETGROUPOWNER msg = (LPDPMSG_SETGROUPOWNER)lpMsg;
715
716       FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
717
718       break;
719     }
720
721     case DPSYS_SENDCOMPLETE:
722     {
723       LPDPMSG_SENDCOMPLETE msg = (LPDPMSG_SENDCOMPLETE)lpMsg;
724
725       FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
726
727       break;
728     }
729
730     default:
731     {
732       /* NOTE: This should be a user defined type. There is nothing that we
733        *       need to do with it except queue it.
734        */
735       TRACE( "Received user message type(?) 0x%08lx through SP.\n",
736               lpMsg->dwType );
737       break;
738     }
739   }
740
741   FIXME( "Queue message in the receive queue. Need some context data!\n" );
742
743   if( FAILED(hr) )
744   {
745     ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType );
746   }
747   /* If a receive event was registered for this player, invoke it */
748   if( hReceiveEvent )
749   {
750     SetEvent( hReceiveEvent );
751   }
752 #endif
753 }
754
755 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
756 ( LPDIRECTPLAYSP iface,
757   DPID idPlayer,
758   LPVOID lpData,
759   DWORD dwDataSize,
760   DWORD dwFlags
761 )
762 {
763   HRESULT           hr;
764   LPDP_SPPLAYERDATA lpPlayerEntry;
765   LPVOID            lpPlayerData;
766
767   ICOM_THIS(IDirectPlaySPImpl,iface);
768
769 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
770   TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n",
771          This, idPlayer, lpData, dwDataSize, dwFlags );
772
773   hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
774   if( FAILED(hr) )
775   {
776     /* Player must not exist */
777     return DPERR_INVALIDPLAYER;
778   }
779
780   lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
781   CopyMemory( lpPlayerData, lpData, dwDataSize );
782
783   if( dwFlags == DPSET_LOCAL )
784   {
785     lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
786     lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
787   }
788   else if( dwFlags == DPSET_REMOTE )
789   {
790     lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
791     lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
792   }
793
794   hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
795
796   return hr;
797 }
798
799 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
800 ( LPDIRECTPLAYSP iface,
801   LPCDPCOMPOUNDADDRESSELEMENT lpElements,
802   DWORD dwElementCount,
803   LPVOID lpAddress,
804   LPDWORD lpdwAddressSize
805 )
806 {
807   ICOM_THIS(IDirectPlaySPImpl,iface);
808
809   FIXME( "(%p)->(%p,0x%08lx,%p,%p): stub\n",
810          This, lpElements, dwElementCount, lpAddress, lpdwAddressSize );
811
812   return DP_OK;
813 }
814
815 static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
816 ( LPDIRECTPLAYSP iface,
817   LPVOID* lplpData,
818   LPDWORD lpdwDataSize,
819   DWORD dwFlags
820 )
821 {
822   HRESULT hr = DP_OK;
823   ICOM_THIS(IDirectPlaySPImpl,iface);
824
825 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
826   TRACE( "(%p)->(%p,%p,0x%08lx)\n",
827          This, lplpData, lpdwDataSize, dwFlags );
828
829 #if 0
830   /* This is what the documentation says... */
831   if( dwFlags != DPSET_REMOTE )
832   {
833     return DPERR_INVALIDPARAMS;
834   }
835 #else
836   /* ... but most service providers call this with 1 */
837   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
838    * thing?
839    */
840   if( dwFlags != DPSET_REMOTE )
841   {
842     TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
843   }
844 #endif
845
846   /* FIXME: What to do in the case where this isn't initialized yet? */
847
848   /* Yes, we're supposed to return a pointer to the memory we have stored! */
849   if( dwFlags == DPSET_REMOTE )
850   {
851     *lpdwDataSize = This->sp->dwSpRemoteDataSize;
852     *lplpData     = This->sp->lpSpRemoteData;
853
854     if( This->sp->lpSpRemoteData == NULL )
855     {
856       hr = DPERR_GENERIC;
857     }
858   }
859   else if( dwFlags == DPSET_LOCAL )
860   {
861     *lpdwDataSize = This->sp->dwSpLocalDataSize;
862     *lplpData     = This->sp->lpSpLocalData;
863
864     if( This->sp->lpSpLocalData == NULL )
865     {
866       hr = DPERR_GENERIC;
867     }
868   }
869
870   return hr;
871 }
872
873 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
874 ( LPDIRECTPLAYSP iface,
875   LPVOID lpData,
876   DWORD dwDataSize,
877   DWORD dwFlags
878 )
879 {
880   LPVOID lpSpData;
881
882   ICOM_THIS(IDirectPlaySPImpl,iface);
883
884 /*  TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
885   TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n",
886          This, lpData, dwDataSize, dwFlags );
887
888 #if 0
889   /* This is what the documentation says... */
890   if( dwFlags != DPSET_REMOTE )
891   {
892     return DPERR_INVALIDPARAMS;
893   }
894 #else
895   /* ... but most service providers call this with 1 */
896   /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
897    * thing?
898    */
899   if( dwFlags != DPSET_REMOTE )
900   {
901     TRACE( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
902   }
903 #endif
904
905   lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
906   CopyMemory( lpSpData, lpData, dwDataSize );
907
908   /* If we have data already allocated, free it and replace it */
909   if( dwFlags == DPSET_REMOTE )
910   {
911     if( This->sp->lpSpRemoteData )
912     {
913       HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
914     }
915
916     This->sp->dwSpRemoteDataSize = dwDataSize;
917     This->sp->lpSpRemoteData = lpSpData;
918   }
919   else if ( dwFlags == DPSET_LOCAL )
920   {
921     if( This->sp->lpSpLocalData )
922     {
923       HeapFree( GetProcessHeap(), 0, This->sp->lpSpLocalData );
924     }
925
926     This->sp->lpSpLocalData     = lpSpData;
927     This->sp->dwSpLocalDataSize = dwDataSize;
928   }
929
930   return DP_OK;
931 }
932
933 static VOID WINAPI IDirectPlaySPImpl_SendComplete
934 ( LPDIRECTPLAYSP iface,
935   LPVOID unknownA,
936   DWORD unknownB
937 )
938 {
939   ICOM_THIS(IDirectPlaySPImpl,iface);
940
941   FIXME( "(%p)->(%p,0x%08lx): stub\n",
942          This, unknownA, unknownB );
943 }
944
945
946 static struct ICOM_VTABLE(IDirectPlaySP) directPlaySPVT =
947 {
948   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
949
950   DPSP_QueryInterface,
951   DPSP_AddRef,
952   DPSP_Release,
953
954   IDirectPlaySPImpl_AddMRUEntry,
955   IDirectPlaySPImpl_CreateAddress,
956   IDirectPlaySPImpl_EnumAddress,
957   IDirectPlaySPImpl_EnumMRUEntries,
958   IDirectPlaySPImpl_GetPlayerFlags,
959   IDirectPlaySPImpl_GetSPPlayerData,
960   IDirectPlaySPImpl_HandleMessage,
961   IDirectPlaySPImpl_SetSPPlayerData,
962   IDirectPlaySPImpl_CreateCompoundAddress,
963   IDirectPlaySPImpl_GetSPData,
964   IDirectPlaySPImpl_SetSPData,
965   IDirectPlaySPImpl_SendComplete
966 };
967
968
969 /* DP external interfaces to call into DPSP interface */
970
971 /* Allocate the structure */
972 extern LPVOID DPSP_CreateSPPlayerData(void)
973 {
974   TRACE( "Creating SPPlayer data struct\n" );
975   return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
976                     sizeof( DP_SPPLAYERDATA ) );
977 }
978