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
21 #include "dplayx_global.h"
23 /* FIXME: Need to add interface locking inside procedures */
25 typedef struct IDirectPlaySPImpl
27 IDirectPlaySP IDirectPlaySP_iface
;
30 DWORD remote_data_size
;
32 DWORD local_data_size
;
33 IDirectPlayImpl
*dplay
; /* FIXME: This should perhaps be iface not impl */
36 /* This structure is passed to the DP object for safe keeping */
37 typedef struct tagDP_SPPLAYERDATA
39 LPVOID lpPlayerLocalData
;
40 DWORD dwPlayerLocalDataSize
;
42 LPVOID lpPlayerRemoteData
;
43 DWORD dwPlayerRemoteDataSize
;
44 } DP_SPPLAYERDATA
, *LPDP_SPPLAYERDATA
;
47 static inline IDirectPlaySPImpl
*impl_from_IDirectPlaySP( IDirectPlaySP
*iface
)
49 return CONTAINING_RECORD( iface
, IDirectPlaySPImpl
, IDirectPlaySP_iface
);
52 static HRESULT WINAPI
IDirectPlaySPImpl_QueryInterface( IDirectPlaySP
*iface
, REFIID riid
,
55 TRACE("(%p)->(%s,%p)\n", iface
, debugstr_guid( riid
), ppv
);
57 if ( IsEqualGUID( &IID_IUnknown
, riid
) || IsEqualGUID( &IID_IDirectPlaySP
, riid
) )
60 IDirectPlaySP_AddRef( iface
);
64 FIXME( "Unsupported interface %s\n", debugstr_guid( riid
) );
69 static ULONG WINAPI
IDirectPlaySPImpl_AddRef( IDirectPlaySP
*iface
)
71 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
72 ULONG ref
= InterlockedIncrement( &This
->ref
);
74 TRACE( "(%p) ref=%d\n", This
, ref
);
79 static ULONG WINAPI
IDirectPlaySPImpl_Release( IDirectPlaySP
*iface
)
81 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
82 ULONG ref
= InterlockedDecrement( &This
->ref
);
84 TRACE( "(%p) ref=%d\n", This
, ref
);
88 HeapFree( GetProcessHeap(), 0, This
->remote_data
);
89 HeapFree( GetProcessHeap(), 0, This
->local_data
);
90 HeapFree( GetProcessHeap(), 0, This
);
96 static HRESULT WINAPI
IDirectPlaySPImpl_AddMRUEntry( IDirectPlaySP
*iface
, LPCWSTR lpSection
,
97 LPCWSTR lpKey
, const void *lpData
, DWORD dwDataSize
, DWORD dwMaxEntries
)
99 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
101 /* Should be able to call the comctl32 undocumented MRU routines.
102 I suspect that the interface works appropriately */
103 FIXME( "(%p)->(%p,%p%p,0x%08x,0x%08x): stub\n",
104 This
, lpSection
, lpKey
, lpData
, dwDataSize
, dwMaxEntries
);
109 static HRESULT WINAPI
IDirectPlaySPImpl_CreateAddress( IDirectPlaySP
*iface
, REFGUID guidSP
,
110 REFGUID guidDataType
, const void *lpData
, DWORD dwDataSize
, void *lpAddress
,
111 DWORD
*lpdwAddressSize
)
113 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
115 FIXME( "(%p)->(%s,%s,%p,0x%08x,%p,%p): stub\n",
116 This
, debugstr_guid(guidSP
), debugstr_guid(guidDataType
),
117 lpData
, dwDataSize
, lpAddress
, lpdwAddressSize
);
122 static HRESULT WINAPI
IDirectPlaySPImpl_EnumAddress( IDirectPlaySP
*iface
,
123 LPDPENUMADDRESSCALLBACK lpEnumAddressCallback
, const void *lpAddress
, DWORD dwAddressSize
,
126 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
128 TRACE( "(%p)->(%p,%p,0x%08x,%p)\n",
129 This
, lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
131 DPL_EnumAddress( lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
136 static HRESULT WINAPI
IDirectPlaySPImpl_EnumMRUEntries( IDirectPlaySP
*iface
, LPCWSTR lpSection
,
137 LPCWSTR lpKey
, LPENUMMRUCALLBACK lpEnumMRUCallback
, void *lpContext
)
139 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
141 /* Should be able to call the comctl32 undocumented MRU routines.
142 I suspect that the interface works appropriately */
143 FIXME( "(%p)->(%p,%p,%p,%p): stub\n",
144 This
, lpSection
, lpKey
, lpEnumMRUCallback
, lpContext
);
149 static HRESULT WINAPI
IDirectPlaySPImpl_GetPlayerFlags( IDirectPlaySP
*iface
, DPID idPlayer
,
150 DWORD
*lpdwPlayerFlags
)
152 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
154 FIXME( "(%p)->(0x%08x,%p): stub\n",
155 This
, idPlayer
, lpdwPlayerFlags
);
160 static HRESULT WINAPI
IDirectPlaySPImpl_GetSPPlayerData( IDirectPlaySP
*iface
, DPID idPlayer
,
161 void **lplpData
, DWORD
*lpdwDataSize
, DWORD dwFlags
)
163 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
165 LPDP_SPPLAYERDATA lpPlayerData
;
167 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n",
168 This
, idPlayer
, lplpData
, lpdwDataSize
, dwFlags
);
170 hr
= DP_GetSPPlayerData( This
->dplay
, idPlayer
, (void**)&lpPlayerData
);
174 TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr
) );
175 return DPERR_INVALIDPLAYER
;
178 /* What to do in the case where there is nothing set yet? */
179 if( dwFlags
== DPSET_LOCAL
)
181 *lplpData
= lpPlayerData
->lpPlayerLocalData
;
182 *lpdwDataSize
= lpPlayerData
->dwPlayerLocalDataSize
;
184 else if( dwFlags
== DPSET_REMOTE
)
186 *lplpData
= lpPlayerData
->lpPlayerRemoteData
;
187 *lpdwDataSize
= lpPlayerData
->dwPlayerRemoteDataSize
;
190 if( *lplpData
== NULL
)
198 static HRESULT WINAPI
IDirectPlaySPImpl_HandleMessage( IDirectPlaySP
*iface
, void *lpMessageBody
,
199 DWORD dwMessageBodySize
, void *lpMessageHeader
)
201 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
202 LPDPMSG_SENDENVELOPE lpMsg
= lpMessageBody
;
203 HRESULT hr
= DPERR_GENERIC
;
208 FIXME( "(%p)->(%p,0x%08x,%p): mostly stub\n",
209 This
, lpMessageBody
, dwMessageBodySize
, lpMessageHeader
);
211 wCommandId
= lpMsg
->wCommandId
;
212 wVersion
= lpMsg
->wVersion
;
214 TRACE( "Incoming message has envelope of 0x%08x, %u, %u\n",
215 lpMsg
->dwMagic
, wCommandId
, wVersion
);
217 if( lpMsg
->dwMagic
!= DPMSGMAGIC_DPLAYMSG
)
219 ERR( "Unknown magic 0x%08x!\n", lpMsg
->dwMagic
);
220 return DPERR_GENERIC
;
225 const LPDWORD lpcHeader
= lpMessageHeader
;
227 TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
228 lpcHeader
[0], lpcHeader
[1], lpcHeader
[2], lpcHeader
[3], lpcHeader
[4] );
232 /* Pass everything else to Direct Play */
233 data
.lpMessage
= NULL
;
234 data
.dwMessageSize
= 0;
236 /* Pass this message to the dplay interface to handle */
237 hr
= DP_HandleMessage( This
->dplay
, lpMessageBody
, dwMessageBodySize
, lpMessageHeader
,
238 wCommandId
, wVersion
, &data
.lpMessage
, &data
.dwMessageSize
);
242 ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr
) );
245 /* Do we want a reply? */
246 if( data
.lpMessage
!= NULL
)
248 data
.lpSPMessageHeader
= lpMessageHeader
;
249 data
.idNameServer
= 0;
252 hr
= This
->dplay
->dp2
->spData
.lpCB
->Reply( &data
);
256 ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr
) );
264 HANDLE hReceiveEvent
= 0;
265 /* FIXME: Acquire some sort of interface lock */
266 /* FIXME: Need some sort of context for this callback. Need to determine
267 * how this is actually done with the SP
269 /* FIXME: Who needs to delete the message when done? */
270 switch( lpMsg
->dwType
)
272 case DPSYS_CREATEPLAYERORGROUP
:
274 LPDPMSG_CREATEPLAYERORGROUP msg
= lpMsg
;
276 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
278 hr
= DP_IF_CreatePlayer( This
, lpMessageHeader
, msg
->dpId
,
279 &msg
->dpnName
, 0, msg
->lpData
,
280 msg
->dwDataSize
, msg
->dwFlags
, ... );
282 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
284 /* Group in group situation? */
285 if( msg
->dpIdParent
== DPID_NOPARENT_GROUP
)
287 hr
= DP_IF_CreateGroup( This
, lpMessageHeader
, msg
->dpId
,
288 &msg
->dpnName
, 0, msg
->lpData
,
289 msg
->dwDataSize
, msg
->dwFlags
, ... );
291 else /* Group in Group */
293 hr
= DP_IF_CreateGroupInGroup( This
, lpMessageHeader
, msg
->dpIdParent
,
294 &msg
->dpnName
, 0, msg
->lpData
,
295 msg
->dwDataSize
, msg
->dwFlags
, ... );
300 ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
307 case DPSYS_DESTROYPLAYERORGROUP
:
309 LPDPMSG_DESTROYPLAYERORGROUP msg
= lpMsg
;
311 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
313 hr
= DP_IF_DestroyPlayer( This
, msg
->dpId
, ... );
315 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
317 hr
= DP_IF_DestroyGroup( This
, msg
->dpId
, ... );
321 ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
328 case DPSYS_ADDPLAYERTOGROUP
:
330 LPDPMSG_ADDPLAYERTOGROUP msg
= lpMsg
;
332 hr
= DP_IF_AddPlayerToGroup( This
, msg
->dpIdGroup
, msg
->dpIdPlayer
, ... );
336 case DPSYS_DELETEPLAYERFROMGROUP
:
338 LPDPMSG_DELETEPLAYERFROMGROUP msg
= lpMsg
;
340 hr
= DP_IF_DeletePlayerFromGroup( This
, msg
->dpIdGroup
, msg
->dpIdPlayer
,
346 case DPSYS_SESSIONLOST
:
348 LPDPMSG_SESSIONLOST msg
= lpMsg
;
350 FIXME( "DPSYS_SESSIONLOST not handled\n" );
357 LPDPMSG_HOST msg
= lpMsg
;
359 FIXME( "DPSYS_HOST not handled\n" );
364 case DPSYS_SETPLAYERORGROUPDATA
:
366 LPDPMSG_SETPLAYERORGROUPDATA msg
= lpMsg
;
368 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
370 hr
= DP_IF_SetPlayerData( This
, msg
->dpId
, msg
->lpData
, msg
->dwDataSize
, DPSET_REMOTE
, ... );
372 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
374 hr
= DP_IF_SetGroupData( This
, msg
->dpId
, msg
->lpData
, msg
->dwDataSize
,
379 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
386 case DPSYS_SETPLAYERORGROUPNAME
:
388 LPDPMSG_SETPLAYERORGROUPNAME msg
= lpMsg
;
390 if( msg
->dwPlayerType
== DPPLAYERTYPE_PLAYER
)
392 hr
= DP_IF_SetPlayerName( This
, msg
->dpId
, msg
->dpnName
, ... );
394 else if( msg
->dwPlayerType
== DPPLAYERTYPE_GROUP
)
396 hr
= DP_IF_SetGroupName( This
, msg
->dpId
, msg
->dpnName
, ... );
400 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
407 case DPSYS_SETSESSIONDESC
;
409 LPDPMSG_SETSESSIONDESC msg
= lpMsg
;
411 hr
= DP_IF_SetSessionDesc( This
, &msg
->dpDesc
);
416 case DPSYS_ADDGROUPTOGROUP
:
418 LPDPMSG_ADDGROUPTOGROUP msg
= lpMsg
;
420 hr
= DP_IF_AddGroupToGroup( This
, msg
->dpIdParentGroup
, msg
->dpIdGroup
,
426 case DPSYS_DELETEGROUPFROMGROUP
:
428 LPDPMSG_DELETEGROUPFROMGROUP msg
= lpMsg
;
430 hr
= DP_IF_DeleteGroupFromGroup( This
, msg
->dpIdParentGroup
,
431 msg
->dpIdGroup
, ... );
436 case DPSYS_SECUREMESSAGE
:
438 LPDPMSG_SECUREMESSAGE msg
= lpMsg
;
440 FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );
445 case DPSYS_STARTSESSION
:
447 LPDPMSG_STARTSESSION msg
= lpMsg
;
449 FIXME( "DPSYS_STARTSESSION not implemented\n" );
456 LPDPMSG_CHAT msg
= lpMsg
;
458 FIXME( "DPSYS_CHAT not implemeneted\n" );
463 case DPSYS_SETGROUPOWNER
:
465 LPDPMSG_SETGROUPOWNER msg
= lpMsg
;
467 FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );
472 case DPSYS_SENDCOMPLETE
:
474 LPDPMSG_SENDCOMPLETE msg
= lpMsg
;
476 FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );
483 /* NOTE: This should be a user defined type. There is nothing that we
484 * need to do with it except queue it.
486 TRACE( "Received user message type(?) 0x%08lx through SP.\n",
492 FIXME( "Queue message in the receive queue. Need some context data!\n" );
496 ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg
->dwType
);
498 /* If a receive event was registered for this player, invoke it */
501 SetEvent( hReceiveEvent
);
506 static HRESULT WINAPI
IDirectPlaySPImpl_SetSPPlayerData( IDirectPlaySP
*iface
, DPID idPlayer
,
507 void *lpData
, DWORD dwDataSize
, DWORD dwFlags
)
509 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
511 LPDP_SPPLAYERDATA lpPlayerEntry
;
514 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This
, idPlayer
, lpData
, dwDataSize
, dwFlags
);
516 hr
= DP_GetSPPlayerData( This
->dplay
, idPlayer
, (void**)&lpPlayerEntry
);
519 /* Player must not exist */
520 return DPERR_INVALIDPLAYER
;
523 lpPlayerData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
524 CopyMemory( lpPlayerData
, lpData
, dwDataSize
);
526 if( dwFlags
== DPSET_LOCAL
)
528 lpPlayerEntry
->lpPlayerLocalData
= lpPlayerData
;
529 lpPlayerEntry
->dwPlayerLocalDataSize
= dwDataSize
;
531 else if( dwFlags
== DPSET_REMOTE
)
533 lpPlayerEntry
->lpPlayerRemoteData
= lpPlayerData
;
534 lpPlayerEntry
->dwPlayerRemoteDataSize
= dwDataSize
;
537 hr
= DP_SetSPPlayerData( This
->dplay
, idPlayer
, lpPlayerEntry
);
542 static HRESULT WINAPI
IDirectPlaySPImpl_CreateCompoundAddress( IDirectPlaySP
*iface
,
543 const DPCOMPOUNDADDRESSELEMENT
*lpElements
, DWORD dwElementCount
, void *lpAddress
,
544 DWORD
*lpdwAddressSize
)
546 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
548 FIXME( "(%p)->(%p,0x%08x,%p,%p): stub\n",
549 This
, lpElements
, dwElementCount
, lpAddress
, lpdwAddressSize
);
554 static HRESULT WINAPI
IDirectPlaySPImpl_GetSPData( IDirectPlaySP
*iface
, void **lplpData
,
555 DWORD
*lpdwDataSize
, DWORD dwFlags
)
557 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
560 TRACE( "(%p)->(%p,%p,0x%08x)\n", This
, lplpData
, lpdwDataSize
, dwFlags
);
563 /* This is what the documentation says... */
564 if( dwFlags
!= DPSET_REMOTE
)
566 return DPERR_INVALIDPARAMS
;
569 /* ... but most service providers call this with 1 */
570 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
573 if( dwFlags
!= DPSET_REMOTE
)
575 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
579 /* FIXME: What to do in the case where this isn't initialized yet? */
581 /* Yes, we're supposed to return a pointer to the memory we have stored! */
582 if( dwFlags
== DPSET_REMOTE
)
584 *lpdwDataSize
= This
->remote_data_size
;
585 *lplpData
= This
->remote_data
;
587 if( !This
->remote_data
)
590 else if( dwFlags
== DPSET_LOCAL
)
592 *lpdwDataSize
= This
->local_data_size
;
593 *lplpData
= This
->local_data
;
595 if( !This
->local_data
)
602 static HRESULT WINAPI
IDirectPlaySPImpl_SetSPData( IDirectPlaySP
*iface
, void *lpData
,
603 DWORD dwDataSize
, DWORD dwFlags
)
605 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
608 TRACE( "(%p)->(%p,0x%08x,0x%08x)\n", This
, lpData
, dwDataSize
, dwFlags
);
611 /* This is what the documentation says... */
612 if( dwFlags
!= DPSET_REMOTE
)
614 return DPERR_INVALIDPARAMS
;
617 /* ... but most service providers call this with 1 */
618 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
621 if( dwFlags
!= DPSET_REMOTE
)
623 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
627 lpSpData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
628 CopyMemory( lpSpData
, lpData
, dwDataSize
);
630 /* If we have data already allocated, free it and replace it */
631 if( dwFlags
== DPSET_REMOTE
)
633 HeapFree( GetProcessHeap(), 0, This
->remote_data
);
634 This
->remote_data_size
= dwDataSize
;
635 This
->remote_data
= lpSpData
;
637 else if ( dwFlags
== DPSET_LOCAL
)
639 HeapFree( GetProcessHeap(), 0, This
->local_data
);
640 This
->local_data
= lpSpData
;
641 This
->local_data_size
= dwDataSize
;
647 static void WINAPI
IDirectPlaySPImpl_SendComplete( IDirectPlaySP
*iface
, void *unknownA
,
650 IDirectPlaySPImpl
*This
= impl_from_IDirectPlaySP( iface
);
652 FIXME( "(%p)->(%p,0x%08x): stub\n",
653 This
, unknownA
, unknownB
);
656 static const IDirectPlaySPVtbl directPlaySPVT
=
658 IDirectPlaySPImpl_QueryInterface
,
659 IDirectPlaySPImpl_AddRef
,
660 IDirectPlaySPImpl_Release
,
661 IDirectPlaySPImpl_AddMRUEntry
,
662 IDirectPlaySPImpl_CreateAddress
,
663 IDirectPlaySPImpl_EnumAddress
,
664 IDirectPlaySPImpl_EnumMRUEntries
,
665 IDirectPlaySPImpl_GetPlayerFlags
,
666 IDirectPlaySPImpl_GetSPPlayerData
,
667 IDirectPlaySPImpl_HandleMessage
,
668 IDirectPlaySPImpl_SetSPPlayerData
,
669 IDirectPlaySPImpl_CreateCompoundAddress
,
670 IDirectPlaySPImpl_GetSPData
,
671 IDirectPlaySPImpl_SetSPData
,
672 IDirectPlaySPImpl_SendComplete
675 HRESULT
dplaysp_create( REFIID riid
, void **ppv
, IDirectPlayImpl
*dp
)
677 IDirectPlaySPImpl
*obj
;
680 TRACE( "(%s, %p)\n", debugstr_guid( riid
), ppv
);
683 obj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( *obj
) );
685 return DPERR_OUTOFMEMORY
;
687 obj
->IDirectPlaySP_iface
.lpVtbl
= &directPlaySPVT
;
691 hr
= IDirectPlaySP_QueryInterface( &obj
->IDirectPlaySP_iface
, riid
, ppv
);
692 IDirectPlaySP_Release( &obj
->IDirectPlaySP_iface
);
697 /* DP external interfaces to call into DPSP interface */
699 /* Allocate the structure */
700 LPVOID
DPSP_CreateSPPlayerData(void)
702 TRACE( "Creating SPPlayer data struct\n" );
703 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
704 sizeof( DP_SPPLAYERDATA
) );