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