1 /* This contains the implementation of the interface Service
2 * Providers require to communicate with Direct Play
4 * Copyright 2000 Peter Hunnisett
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.
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.
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
23 #include "wine/debug.h"
25 #include "wine/dplaysp.h"
26 #include "dplay_global.h"
27 #include "name_server.h"
28 #include "dplayx_messages.h"
30 #include "dplayx_global.h" /* FIXME: For global hack */
32 /* FIXME: Need to add interface locking inside procedures */
34 WINE_DEFAULT_DEBUG_CHANNEL(dplay
);
36 typedef struct IDirectPlaySPImpl
38 IDirectPlaySP IDirectPlaySP_iface
;
41 DWORD remote_data_size
;
43 DWORD local_data_size
;
44 IDirectPlayImpl
*dplay
; /* FIXME: This should perhaps be iface not impl */
47 /* This structure is passed to the DP object for safe keeping */
48 typedef struct tagDP_SPPLAYERDATA
50 LPVOID lpPlayerLocalData
;
51 DWORD dwPlayerLocalDataSize
;
53 LPVOID lpPlayerRemoteData
;
54 DWORD dwPlayerRemoteDataSize
;
55 } DP_SPPLAYERDATA
, *LPDP_SPPLAYERDATA
;
58 static inline IDirectPlaySPImpl
*impl_from_IDirectPlaySP( IDirectPlaySP
*iface
)
60 return CONTAINING_RECORD( iface
, IDirectPlaySPImpl
, IDirectPlaySP_iface
);
63 static HRESULT WINAPI
IDirectPlaySPImpl_QueryInterface( IDirectPlaySP
*iface
, REFIID riid
,
66 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid( riid
), ppv
);
68 if ( IsEqualGUID( &IID_IUnknown
, riid
) || IsEqualGUID( &IID_IDirectPlaySP
, riid
) )
71 IDirectPlaySP_AddRef( iface
);
75 FIXME( "Unsupported interface %s\n", debugstr_guid( riid
) );
80 static ULONG WINAPI
IDirectPlaySPImpl_AddRef( IDirectPlaySP
*iface
)
82 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
83 ULONG ref
= InterlockedIncrement( &This
->ref
);
85 TRACE( "(%p) ref=%d\n", This
, ref
);
90 static ULONG WINAPI
IDirectPlaySPImpl_Release( IDirectPlaySP
*iface
)
92 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
93 ULONG ref
= InterlockedDecrement( &This
->ref
);
95 TRACE( "(%p) ref=%d\n", This
, ref
);
99 HeapFree( GetProcessHeap(), 0, This
->remote_data
);
100 HeapFree( GetProcessHeap(), 0, This
->local_data
);
101 HeapFree( GetProcessHeap(), 0, This
);
107 static HRESULT WINAPI
IDirectPlaySPImpl_AddMRUEntry( IDirectPlaySP
*iface
, LPCWSTR lpSection
,
108 LPCWSTR lpKey
, const void *lpData
, DWORD dwDataSize
, DWORD dwMaxEntries
)
110 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
112 /* Should be able to call the comctl32 undocumented MRU routines.
113 I suspect that the interface works appropriately */
114 FIXME( "(%p)->(%p,%p%p,0x%08x,0x%08x): stub\n",
115 This
, lpSection
, lpKey
, lpData
, dwDataSize
, dwMaxEntries
);
120 static HRESULT WINAPI
IDirectPlaySPImpl_CreateAddress( IDirectPlaySP
*iface
, REFGUID guidSP
,
121 REFGUID guidDataType
, const void *lpData
, DWORD dwDataSize
, void *lpAddress
,
122 DWORD
*lpdwAddressSize
)
124 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
126 FIXME( "(%p)->(%s,%s,%p,0x%08x,%p,%p): stub\n",
127 This
, debugstr_guid(guidSP
), debugstr_guid(guidDataType
),
128 lpData
, dwDataSize
, lpAddress
, lpdwAddressSize
);
133 static HRESULT WINAPI
IDirectPlaySPImpl_EnumAddress( IDirectPlaySP
*iface
,
134 LPDPENUMADDRESSCALLBACK lpEnumAddressCallback
, const void *lpAddress
, DWORD dwAddressSize
,
137 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
139 TRACE( "(%p)->(%p,%p,0x%08x,%p)\n",
140 This
, lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
142 DPL_EnumAddress( lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
147 static HRESULT WINAPI
IDirectPlaySPImpl_EnumMRUEntries( IDirectPlaySP
*iface
, LPCWSTR lpSection
,
148 LPCWSTR lpKey
, LPENUMMRUCALLBACK lpEnumMRUCallback
, void *lpContext
)
150 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
152 /* Should be able to call the comctl32 undocumented MRU routines.
153 I suspect that the interface works appropriately */
154 FIXME( "(%p)->(%p,%p,%p,%p): stub\n",
155 This
, lpSection
, lpKey
, lpEnumMRUCallback
, lpContext
);
160 static HRESULT WINAPI
IDirectPlaySPImpl_GetPlayerFlags( IDirectPlaySP
*iface
, DPID idPlayer
,
161 DWORD
*lpdwPlayerFlags
)
163 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
165 FIXME( "(%p)->(0x%08x,%p): stub\n",
166 This
, idPlayer
, lpdwPlayerFlags
);
171 static HRESULT WINAPI
IDirectPlaySPImpl_GetSPPlayerData( IDirectPlaySP
*iface
, DPID idPlayer
,
172 void **lplpData
, DWORD
*lpdwDataSize
, DWORD dwFlags
)
174 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
176 LPDP_SPPLAYERDATA lpPlayerData
;
178 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n",
179 This
, idPlayer
, lplpData
, lpdwDataSize
, dwFlags
);
181 hr
= DP_GetSPPlayerData( This
->dplay
, idPlayer
, (void**)&lpPlayerData
);
185 TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr
) );
186 return DPERR_INVALIDPLAYER
;
189 /* What to do in the case where there is nothing set yet? */
190 if( dwFlags
== DPSET_LOCAL
)
192 *lplpData
= lpPlayerData
->lpPlayerLocalData
;
193 *lpdwDataSize
= lpPlayerData
->dwPlayerLocalDataSize
;
195 else if( dwFlags
== DPSET_REMOTE
)
197 *lplpData
= lpPlayerData
->lpPlayerRemoteData
;
198 *lpdwDataSize
= lpPlayerData
->dwPlayerRemoteDataSize
;
201 if( *lplpData
== NULL
)
209 static HRESULT WINAPI
IDirectPlaySPImpl_HandleMessage( IDirectPlaySP
*iface
, void *lpMessageBody
,
210 DWORD dwMessageBodySize
, void *lpMessageHeader
)
212 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
213 LPDPMSG_SENDENVELOPE lpMsg
= lpMessageBody
;
214 HRESULT hr
= DPERR_GENERIC
;
219 FIXME( "(%p)->(%p,0x%08x,%p): mostly stub\n",
220 This
, lpMessageBody
, dwMessageBodySize
, lpMessageHeader
);
222 wCommandId
= lpMsg
->wCommandId
;
223 wVersion
= lpMsg
->wVersion
;
225 TRACE( "Incoming message has envelope of 0x%08x, %u, %u\n",
226 lpMsg
->dwMagic
, wCommandId
, wVersion
);
228 if( lpMsg
->dwMagic
!= DPMSGMAGIC_DPLAYMSG
)
230 ERR( "Unknown magic 0x%08x!\n", lpMsg
->dwMagic
);
231 return DPERR_GENERIC
;
236 const LPDWORD lpcHeader
= lpMessageHeader
;
238 TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
239 lpcHeader
[0], lpcHeader
[1], lpcHeader
[2], lpcHeader
[3], lpcHeader
[4] );
243 /* Pass everything else to Direct Play */
244 data
.lpMessage
= NULL
;
245 data
.dwMessageSize
= 0;
247 /* Pass this message to the dplay interface to handle */
248 hr
= DP_HandleMessage( This
->dplay
, lpMessageBody
, dwMessageBodySize
, lpMessageHeader
,
249 wCommandId
, wVersion
, &data
.lpMessage
, &data
.dwMessageSize
);
253 ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr
) );
256 /* Do we want a reply? */
257 if( data
.lpMessage
!= NULL
)
259 data
.lpSPMessageHeader
= lpMessageHeader
;
260 data
.idNameServer
= 0;
263 hr
= This
->dplay
->dp2
->spData
.lpCB
->Reply( &data
);
267 ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr
) );
275 HANDLE hReceiveEvent
= 0;
276 /* FIXME: Acquire some sort of interface lock */
277 /* FIXME: Need some sort of context for this callback. Need to determine
278 * how this is actually done with the SP
280 /* FIXME: Who needs to delete the message when done? */
281 switch( lpMsg
->dwType
)
283 case DPSYS_CREATEPLAYERORGROUP
:
285 LPDPMSG_CREATEPLAYERORGROUP msg
= lpMsg
;
287 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
289 hr
= DP_IF_CreatePlayer( This
, lpMessageHeader
, msg
->dpId
,
290 &msg
->dpnName
, 0, msg
->lpData
,
291 msg
->dwDataSize
, msg
->dwFlags
, ... );
293 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
295 /* Group in group situation? */
296 if( msg
->dpIdParent
== DPID_NOPARENT_GROUP
)
298 hr
= DP_IF_CreateGroup( This
, lpMessageHeader
, msg
->dpId
,
299 &msg
->dpnName
, 0, msg
->lpData
,
300 msg
->dwDataSize
, msg
->dwFlags
, ... );
302 else /* Group in Group */
304 hr
= DP_IF_CreateGroupInGroup( This
, lpMessageHeader
, msg
->dpIdParent
,
305 &msg
->dpnName
, 0, msg
->lpData
,
306 msg
->dwDataSize
, msg
->dwFlags
, ... );
311 ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
318 case DPSYS_DESTROYPLAYERORGROUP
:
320 LPDPMSG_DESTROYPLAYERORGROUP msg
= lpMsg
;
322 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
324 hr
= DP_IF_DestroyPlayer( This
, msg
->dpId
, ... );
326 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
328 hr
= DP_IF_DestroyGroup( This
, msg
->dpId
, ... );
332 ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
339 case DPSYS_ADDPLAYERTOGROUP
:
341 LPDPMSG_ADDPLAYERTOGROUP msg
= lpMsg
;
343 hr
= DP_IF_AddPlayerToGroup( This
, msg
->dpIdGroup
, msg
->dpIdPlayer
, ... );
347 case DPSYS_DELETEPLAYERFROMGROUP
:
349 LPDPMSG_DELETEPLAYERFROMGROUP msg
= lpMsg
;
351 hr
= DP_IF_DeletePlayerFromGroup( This
, msg
->dpIdGroup
, msg
->dpIdPlayer
,
357 case DPSYS_SESSIONLOST
:
359 LPDPMSG_SESSIONLOST msg
= lpMsg
;
361 FIXME( "DPSYS_SESSIONLOST not handled\n" );
368 LPDPMSG_HOST msg
= lpMsg
;
370 FIXME( "DPSYS_HOST not handled\n" );
375 case DPSYS_SETPLAYERORGROUPDATA
:
377 LPDPMSG_SETPLAYERORGROUPDATA msg
= lpMsg
;
379 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
381 hr
= DP_IF_SetPlayerData( This
, msg
->dpId
, msg
->lpData
, msg
->dwDataSize
, DPSET_REMOTE
, ... );
383 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
385 hr
= DP_IF_SetGroupData( This
, msg
->dpId
, msg
->lpData
, msg
->dwDataSize
,
390 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
397 case DPSYS_SETPLAYERORGROUPNAME
:
399 LPDPMSG_SETPLAYERORGROUPNAME msg
= lpMsg
;
401 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
403 hr
= DP_IF_SetPlayerName( This
, msg
->dpId
, msg
->dpnName
, ... );
405 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
407 hr
= DP_IF_SetGroupName( This
, msg
->dpId
, msg
->dpnName
, ... );
411 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
418 case DPSYS_SETSESSIONDESC
;
420 LPDPMSG_SETSESSIONDESC msg
= lpMsg
;
422 hr
= DP_IF_SetSessionDesc( This
, &msg
->dpDesc
);
427 case DPSYS_ADDGROUPTOGROUP
:
429 LPDPMSG_ADDGROUPTOGROUP msg
= lpMsg
;
431 hr
= DP_IF_AddGroupToGroup( This
, msg
->dpIdParentGroup
, msg
->dpIdGroup
,
437 case DPSYS_DELETEGROUPFROMGROUP
:
439 LPDPMSG_DELETEGROUPFROMGROUP msg
= lpMsg
;
441 hr
= DP_IF_DeleteGroupFromGroup( This
, msg
->dpIdParentGroup
,
442 msg
->dpIdGroup
, ... );
447 case DPSYS_SECUREMESSAGE
:
449 LPDPMSG_SECUREMESSAGE msg
= lpMsg
;
451 FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
456 case DPSYS_STARTSESSION
:
458 LPDPMSG_STARTSESSION msg
= lpMsg
;
460 FIXME( "DPSYS_STARTSESSION not implemented\n" );
467 LPDPMSG_CHAT msg
= lpMsg
;
469 FIXME( "DPSYS_CHAT not implemeneted\n" );
474 case DPSYS_SETGROUPOWNER
:
476 LPDPMSG_SETGROUPOWNER msg
= lpMsg
;
478 FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
483 case DPSYS_SENDCOMPLETE
:
485 LPDPMSG_SENDCOMPLETE msg
= lpMsg
;
487 FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
494 /* NOTE: This should be a user defined type. There is nothing that we
495 * need to do with it except queue it.
497 TRACE( "Received user message type(?) 0x%08lx through SP.\n",
503 FIXME( "Queue message in the receive queue. Need some context data!\n" );
507 ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg
->dwType
);
509 /* If a receive event was registered for this player, invoke it */
512 SetEvent( hReceiveEvent
);
517 static HRESULT WINAPI
IDirectPlaySPImpl_SetSPPlayerData( IDirectPlaySP
*iface
, DPID idPlayer
,
518 void *lpData
, DWORD dwDataSize
, DWORD dwFlags
)
520 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
522 LPDP_SPPLAYERDATA lpPlayerEntry
;
525 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This
, idPlayer
, lpData
, dwDataSize
, dwFlags
);
527 hr
= DP_GetSPPlayerData( This
->dplay
, idPlayer
, (void**)&lpPlayerEntry
);
530 /* Player must not exist */
531 return DPERR_INVALIDPLAYER
;
534 lpPlayerData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
535 CopyMemory( lpPlayerData
, lpData
, dwDataSize
);
537 if( dwFlags
== DPSET_LOCAL
)
539 lpPlayerEntry
->lpPlayerLocalData
= lpPlayerData
;
540 lpPlayerEntry
->dwPlayerLocalDataSize
= dwDataSize
;
542 else if( dwFlags
== DPSET_REMOTE
)
544 lpPlayerEntry
->lpPlayerRemoteData
= lpPlayerData
;
545 lpPlayerEntry
->dwPlayerRemoteDataSize
= dwDataSize
;
548 hr
= DP_SetSPPlayerData( This
->dplay
, idPlayer
, lpPlayerEntry
);
553 static HRESULT WINAPI
IDirectPlaySPImpl_CreateCompoundAddress( IDirectPlaySP
*iface
,
554 const DPCOMPOUNDADDRESSELEMENT
*lpElements
, DWORD dwElementCount
, void *lpAddress
,
555 DWORD
*lpdwAddressSize
)
557 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
559 FIXME( "(%p)->(%p,0x%08x,%p,%p): stub\n",
560 This
, lpElements
, dwElementCount
, lpAddress
, lpdwAddressSize
);
565 static HRESULT WINAPI
IDirectPlaySPImpl_GetSPData( IDirectPlaySP
*iface
, void **lplpData
,
566 DWORD
*lpdwDataSize
, DWORD dwFlags
)
568 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
571 TRACE( "(%p)->(%p,%p,0x%08x)\n", This
, lplpData
, lpdwDataSize
, dwFlags
);
574 /* This is what the documentation says... */
575 if( dwFlags
!= DPSET_REMOTE
)
577 return DPERR_INVALIDPARAMS
;
580 /* ... but most service providers call this with 1 */
581 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
584 if( dwFlags
!= DPSET_REMOTE
)
586 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
590 /* FIXME: What to do in the case where this isn't initialized yet? */
592 /* Yes, we're supposed to return a pointer to the memory we have stored! */
593 if( dwFlags
== DPSET_REMOTE
)
595 *lpdwDataSize
= This
->remote_data_size
;
596 *lplpData
= This
->remote_data
;
598 if( !This
->remote_data
)
601 else if( dwFlags
== DPSET_LOCAL
)
603 *lpdwDataSize
= This
->local_data_size
;
604 *lplpData
= This
->local_data
;
606 if( !This
->local_data
)
613 static HRESULT WINAPI
IDirectPlaySPImpl_SetSPData( IDirectPlaySP
*iface
, void *lpData
,
614 DWORD dwDataSize
, DWORD dwFlags
)
616 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
619 TRACE( "(%p)->(%p,0x%08x,0x%08x)\n", This
, lpData
, dwDataSize
, dwFlags
);
622 /* This is what the documentation says... */
623 if( dwFlags
!= DPSET_REMOTE
)
625 return DPERR_INVALIDPARAMS
;
628 /* ... but most service providers call this with 1 */
629 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
632 if( dwFlags
!= DPSET_REMOTE
)
634 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
638 lpSpData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
639 CopyMemory( lpSpData
, lpData
, dwDataSize
);
641 /* If we have data already allocated, free it and replace it */
642 if( dwFlags
== DPSET_REMOTE
)
644 HeapFree( GetProcessHeap(), 0, This
->remote_data
);
645 This
->remote_data_size
= dwDataSize
;
646 This
->remote_data
= lpSpData
;
648 else if ( dwFlags
== DPSET_LOCAL
)
650 HeapFree( GetProcessHeap(), 0, This
->local_data
);
651 This
->local_data
= lpSpData
;
652 This
->local_data_size
= dwDataSize
;
658 static void WINAPI
IDirectPlaySPImpl_SendComplete( IDirectPlaySP
*iface
, void *unknownA
,
661 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
663 FIXME( "(%p)->(%p,0x%08x): stub\n",
664 This
, unknownA
, unknownB
);
667 static const IDirectPlaySPVtbl directPlaySPVT
=
669 IDirectPlaySPImpl_QueryInterface
,
670 IDirectPlaySPImpl_AddRef
,
671 IDirectPlaySPImpl_Release
,
672 IDirectPlaySPImpl_AddMRUEntry
,
673 IDirectPlaySPImpl_CreateAddress
,
674 IDirectPlaySPImpl_EnumAddress
,
675 IDirectPlaySPImpl_EnumMRUEntries
,
676 IDirectPlaySPImpl_GetPlayerFlags
,
677 IDirectPlaySPImpl_GetSPPlayerData
,
678 IDirectPlaySPImpl_HandleMessage
,
679 IDirectPlaySPImpl_SetSPPlayerData
,
680 IDirectPlaySPImpl_CreateCompoundAddress
,
681 IDirectPlaySPImpl_GetSPData
,
682 IDirectPlaySPImpl_SetSPData
,
683 IDirectPlaySPImpl_SendComplete
686 HRESULT
dplaysp_create( REFIID riid
, void **ppv
, IDirectPlayImpl
*dp
)
688 IDirectPlaySPImpl
*obj
;
691 TRACE( "(%s, %p)\n", debugstr_guid( riid
), ppv
);
694 obj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( *obj
) );
696 return DPERR_OUTOFMEMORY
;
698 obj
->IDirectPlaySP_iface
.lpVtbl
= &directPlaySPVT
;
702 hr
= IDirectPlaySP_QueryInterface( &obj
->IDirectPlaySP_iface
, riid
, ppv
);
703 IDirectPlaySP_Release( &obj
->IDirectPlaySP_iface
);
708 /* DP external interfaces to call into DPSP interface */
710 /* Allocate the structure */
711 LPVOID
DPSP_CreateSPPlayerData(void)
713 TRACE( "Creating SPPlayer data struct\n" );
714 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
715 sizeof( DP_SPPLAYERDATA
) );