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