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"
26 #include "wine/dplaysp.h"
27 #include "dplay_global.h"
28 #include "name_server.h"
29 #include "dplayx_messages.h"
31 #include "dplayx_global.h" /* FIXME: For global hack */
33 /* FIXME: Need to add interface locking inside procedures */
35 WINE_DEFAULT_DEBUG_CHANNEL(dplay
);
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
);
43 /* Predefine the interface */
44 typedef struct IDirectPlaySPImpl IDirectPlaySPImpl
;
46 typedef struct tagDirectPlaySPIUnknownData
49 CRITICAL_SECTION DPSP_lock
;
50 } DirectPlaySPIUnknownData
;
52 typedef struct tagDirectPlaySPData
54 LPVOID lpSpRemoteData
;
55 DWORD dwSpRemoteDataSize
; /* Size of data pointed to by lpSpRemoteData */
58 DWORD dwSpLocalDataSize
; /* Size of data pointed to by lpSpLocalData */
60 IDirectPlay2Impl
* dplay
; /* FIXME: This should perhaps be iface not impl */
64 #define DPSP_IMPL_FIELDS \
65 LONG ulInterfaceRef; \
66 DirectPlaySPIUnknownData* unk; \
69 struct IDirectPlaySPImpl
71 const IDirectPlaySPVtbl
*lpVtbl
;
75 /* Forward declaration of virtual tables */
76 static const IDirectPlaySPVtbl directPlaySPVT
;
78 /* This structure is passed to the DP object for safe keeping */
79 typedef struct tagDP_SPPLAYERDATA
81 LPVOID lpPlayerLocalData
;
82 DWORD dwPlayerLocalDataSize
;
84 LPVOID lpPlayerRemoteData
;
85 DWORD dwPlayerRemoteDataSize
;
86 } DP_SPPLAYERDATA
, *LPDP_SPPLAYERDATA
;
88 /* Create the SP interface */
89 HRESULT
DPSP_CreateInterface( REFIID riid
, LPVOID
* ppvObj
, IDirectPlay2Impl
* dp
)
91 TRACE( " for %s\n", debugstr_guid( riid
) );
93 *ppvObj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
94 sizeof( IDirectPlaySPImpl
) );
98 return DPERR_OUTOFMEMORY
;
101 if( IsEqualGUID( &IID_IDirectPlaySP
, riid
) )
103 IDirectPlaySPImpl
*This
= *ppvObj
;
104 This
->lpVtbl
= &directPlaySPVT
;
108 /* Unsupported interface */
109 HeapFree( GetProcessHeap(), 0, *ppvObj
);
112 return E_NOINTERFACE
;
116 if( DPSP_CreateIUnknown( *ppvObj
) &&
117 DPSP_CreateDirectPlaySP( *ppvObj
, dp
)
120 IDirectPlaySP_AddRef( (LPDIRECTPLAYSP
)*ppvObj
);
124 /* Initialize failed, destroy it */
125 DPSP_DestroyDirectPlaySP( *ppvObj
);
126 DPSP_DestroyIUnknown( *ppvObj
);
128 HeapFree( GetProcessHeap(), 0, *ppvObj
);
131 return DPERR_NOMEMORY
;
134 static BOOL
DPSP_CreateIUnknown( LPVOID lpSP
)
136 IDirectPlaySPImpl
*This
= lpSP
;
138 This
->unk
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( *(This
->unk
) ) );
140 if ( This
->unk
== NULL
)
145 InitializeCriticalSection( &This
->unk
->DPSP_lock
);
146 This
->unk
->DPSP_lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IDirectPlaySPImpl*->DirectPlaySPIUnknownData*->DPSP_lock");
151 static BOOL
DPSP_DestroyIUnknown( LPVOID lpSP
)
153 IDirectPlaySPImpl
*This
= lpSP
;
155 This
->unk
->DPSP_lock
.DebugInfo
->Spare
[0] = 0;
156 DeleteCriticalSection( &This
->unk
->DPSP_lock
);
157 HeapFree( GetProcessHeap(), 0, This
->unk
);
163 static BOOL
DPSP_CreateDirectPlaySP( LPVOID lpSP
, IDirectPlay2Impl
* dp
)
165 IDirectPlaySPImpl
*This
= lpSP
;
167 This
->sp
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( *(This
->sp
) ) );
169 if ( This
->sp
== NULL
)
174 This
->sp
->dplay
= dp
;
176 /* Normally we should be keeping a reference, but since only the dplay
177 * interface that created us can destroy us, we do not keep a reference
178 * to it (ie we'd be stuck with always having one reference to the dplay
179 * object, and hence us, around).
180 * NOTE: The dp object does reference count us.
182 * FIXME: This is a kludge to get around a problem where a queryinterface
183 * is used to get a new interface and then is closed. We will then
184 * reference garbage. However, with this we will never deallocate
185 * the interface we store. The correct fix is to require all
186 * DP internal interfaces to use the This->dp2 interface which
187 * should be changed to This->dp
189 IDirectPlayX_AddRef( (LPDIRECTPLAY2
)dp
);
194 static BOOL
DPSP_DestroyDirectPlaySP( LPVOID lpSP
)
196 IDirectPlaySPImpl
*This
= lpSP
;
198 /* Normally we should be keeping a reference, but since only the dplay
199 * interface that created us can destroy us, we do not keep a reference
200 * to it (ie we'd be stuck with always having one reference to the dplay
201 * object, and hence us, around).
202 * NOTE: The dp object does reference count us.
204 /*IDirectPlayX_Release( (LPDIRECTPLAY2)This->sp->dplay ); */
206 HeapFree( GetProcessHeap(), 0, This
->sp
->lpSpRemoteData
);
207 HeapFree( GetProcessHeap(), 0, This
->sp
->lpSpLocalData
);
209 /* FIXME: Need to delete player queue */
211 HeapFree( GetProcessHeap(), 0, This
->sp
);
215 /* Interface implementation */
217 static HRESULT WINAPI DPSP_QueryInterface
218 ( LPDIRECTPLAYSP iface
,
222 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
223 TRACE("(%p)->(%s,%p)\n", This
, debugstr_guid( riid
), ppvObj
);
225 *ppvObj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
228 if( *ppvObj
== NULL
)
230 return DPERR_OUTOFMEMORY
;
233 CopyMemory( *ppvObj
, This
, sizeof( *This
) );
234 (*(IDirectPlaySPImpl
**)ppvObj
)->ulInterfaceRef
= 0;
236 if( IsEqualGUID( &IID_IDirectPlaySP
, riid
) )
238 IDirectPlaySPImpl
*This
= *ppvObj
;
239 This
->lpVtbl
= &directPlaySPVT
;
243 /* Unsupported interface */
244 HeapFree( GetProcessHeap(), 0, *ppvObj
);
247 return E_NOINTERFACE
;
250 IDirectPlaySP_AddRef( (LPDIRECTPLAYSP
)*ppvObj
);
255 static ULONG WINAPI DPSP_AddRef
256 ( LPDIRECTPLAYSP iface
)
258 ULONG ulInterfaceRefCount
, ulObjRefCount
;
259 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
261 ulObjRefCount
= InterlockedIncrement( &This
->unk
->ulObjRef
);
262 ulInterfaceRefCount
= InterlockedIncrement( &This
->ulInterfaceRef
);
264 TRACE( "ref count incremented to %u:%u for %p\n",
265 ulInterfaceRefCount
, ulObjRefCount
, This
);
267 return ulObjRefCount
;
270 static ULONG WINAPI DPSP_Release
271 ( LPDIRECTPLAYSP iface
)
273 ULONG ulInterfaceRefCount
, ulObjRefCount
;
274 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
276 ulObjRefCount
= InterlockedDecrement( &This
->unk
->ulObjRef
);
277 ulInterfaceRefCount
= InterlockedDecrement( &This
->ulInterfaceRef
);
279 TRACE( "ref count decremented to %u:%u for %p\n",
280 ulInterfaceRefCount
, ulObjRefCount
, This
);
282 /* Deallocate if this is the last reference to the object */
283 if( ulObjRefCount
== 0 )
285 DPSP_DestroyDirectPlaySP( This
);
286 DPSP_DestroyIUnknown( This
);
289 if( ulInterfaceRefCount
== 0 )
291 HeapFree( GetProcessHeap(), 0, This
);
294 return ulInterfaceRefCount
;
297 static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry
298 ( LPDIRECTPLAYSP iface
,
306 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
308 /* Should be able to call the comctl32 undocumented MRU routines.
309 I suspect that the interface works appropriately */
310 FIXME( "(%p)->(%p,%p%p,0x%08x,0x%08x): stub\n",
311 This
, lpSection
, lpKey
, lpData
, dwDataSize
, dwMaxEntries
);
316 static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress
317 ( LPDIRECTPLAYSP iface
,
319 REFGUID guidDataType
,
323 LPDWORD lpdwAddressSize
326 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
328 FIXME( "(%p)->(%s,%s,%p,0x%08x,%p,%p): stub\n",
329 This
, debugstr_guid(guidSP
), debugstr_guid(guidDataType
),
330 lpData
, dwDataSize
, lpAddress
, lpdwAddressSize
);
335 static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress
336 ( LPDIRECTPLAYSP iface
,
337 LPDPENUMADDRESSCALLBACK lpEnumAddressCallback
,
343 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
345 TRACE( "(%p)->(%p,%p,0x%08x,%p)\n",
346 This
, lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
348 DPL_EnumAddress( lpEnumAddressCallback
, lpAddress
, dwAddressSize
, lpContext
);
353 static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries
354 ( LPDIRECTPLAYSP iface
,
357 LPENUMMRUCALLBACK lpEnumMRUCallback
,
361 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
363 /* Should be able to call the comctl32 undocumented MRU routines.
364 I suspect that the interface works appropriately */
365 FIXME( "(%p)->(%p,%p,%p,%p,): stub\n",
366 This
, lpSection
, lpKey
, lpEnumMRUCallback
, lpContext
);
371 static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags
372 ( LPDIRECTPLAYSP iface
,
374 LPDWORD lpdwPlayerFlags
377 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
379 FIXME( "(%p)->(0x%08x,%p): stub\n",
380 This
, idPlayer
, lpdwPlayerFlags
);
385 static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
386 ( LPDIRECTPLAYSP iface
,
389 LPDWORD lpdwDataSize
,
394 LPDP_SPPLAYERDATA lpPlayerData
;
395 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
397 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n",
398 This
, idPlayer
, lplpData
, lpdwDataSize
, dwFlags
);
400 hr
= DP_GetSPPlayerData( This
->sp
->dplay
, idPlayer
, (LPVOID
*)&lpPlayerData
);
404 TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr
) );
405 return DPERR_INVALIDPLAYER
;
408 /* What to do in the case where there is nothing set yet? */
409 if( dwFlags
== DPSET_LOCAL
)
411 HeapFree( GetProcessHeap(), 0, lpPlayerData
->lpPlayerLocalData
);
412 *lplpData
= lpPlayerData
->lpPlayerLocalData
;
413 *lpdwDataSize
= lpPlayerData
->dwPlayerLocalDataSize
;
415 else if( dwFlags
== DPSET_REMOTE
)
417 HeapFree( GetProcessHeap(), 0, lpPlayerData
->lpPlayerRemoteData
);
418 *lplpData
= lpPlayerData
->lpPlayerRemoteData
;
419 *lpdwDataSize
= lpPlayerData
->dwPlayerRemoteDataSize
;
422 if( *lplpData
== NULL
)
430 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
431 ( LPDIRECTPLAYSP iface
,
432 LPVOID lpMessageBody
,
433 DWORD dwMessageBodySize
,
434 LPVOID lpMessageHeader
437 LPDPSP_MSG_ENVELOPE lpMsg
= lpMessageBody
;
441 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
443 TRACE( "(%p)->(%p,0x%08x,%p)\n",
444 This
, lpMessageBody
, dwMessageBodySize
, lpMessageHeader
);
446 TRACE( "Incoming message has envelope of 0x%08x, 0x%x, %u\n",
447 lpMsg
->dwMagic
, lpMsg
->wCommandId
, lpMsg
->wVersion
);
449 if( lpMsg
->dwMagic
!= DPMSG_SIGNATURE
)
451 ERR( "Unknown magic 0x%08x!\n", lpMsg
->dwMagic
);
452 return DPERR_GENERIC
;
455 /* Pass everything else to Direct Play */
456 data
.lpMessage
= NULL
;
457 data
.dwMessageSize
= 0;
459 /* Pass this message to the dplay interface to handle */
460 hr
= DP_HandleMessage( This
->sp
->dplay
, lpMessageBody
, dwMessageBodySize
,
461 lpMessageHeader
, lpMsg
->wCommandId
, lpMsg
->wVersion
,
462 &data
.lpMessage
, &data
.dwMessageSize
);
465 ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr
) );
468 /* Do we want a reply? */
469 if( data
.lpMessage
!= NULL
)
471 data
.lpSPMessageHeader
= lpMessageHeader
;
472 data
.idNameServer
= 0;
475 hr
= (This
->sp
->dplay
->dp2
->spData
.lpCB
->Reply
)( &data
);
479 ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr
) );
486 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
487 ( LPDIRECTPLAYSP iface
,
495 LPDP_SPPLAYERDATA lpPlayerEntry
;
498 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
500 /* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
501 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n",
502 This
, idPlayer
, lpData
, dwDataSize
, dwFlags
);
504 hr
= DP_GetSPPlayerData( This
->sp
->dplay
, idPlayer
, (LPVOID
*)&lpPlayerEntry
);
507 /* Player must not exist */
508 return DPERR_INVALIDPLAYER
;
511 lpPlayerData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
512 CopyMemory( lpPlayerData
, lpData
, dwDataSize
);
514 if( dwFlags
== DPSET_LOCAL
)
516 lpPlayerEntry
->lpPlayerLocalData
= lpPlayerData
;
517 lpPlayerEntry
->dwPlayerLocalDataSize
= dwDataSize
;
519 else if( dwFlags
== DPSET_REMOTE
)
521 lpPlayerEntry
->lpPlayerRemoteData
= lpPlayerData
;
522 lpPlayerEntry
->dwPlayerRemoteDataSize
= dwDataSize
;
525 hr
= DP_SetSPPlayerData( This
->sp
->dplay
, idPlayer
, lpPlayerEntry
);
530 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
531 ( LPDIRECTPLAYSP iface
,
532 LPCDPCOMPOUNDADDRESSELEMENT lpElements
,
533 DWORD dwElementCount
,
535 LPDWORD lpdwAddressSize
538 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
540 FIXME( "(%p)->(%p,0x%08x,%p,%p): stub\n",
541 This
, lpElements
, dwElementCount
, lpAddress
, lpdwAddressSize
);
546 static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
547 ( LPDIRECTPLAYSP iface
,
549 LPDWORD lpdwDataSize
,
554 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
556 /* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
557 TRACE( "(%p)->(%p,%p,0x%08x)\n",
558 This
, lplpData
, lpdwDataSize
, dwFlags
);
561 /* This is what the documentation says... */
562 if( dwFlags
!= DPSET_REMOTE
)
564 return DPERR_INVALIDPARAMS
;
567 /* ... but most service providers call this with 1 */
568 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
571 if( dwFlags
!= DPSET_REMOTE
)
573 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
577 /* FIXME: What to do in the case where this isn't initialized yet? */
579 /* Yes, we're supposed to return a pointer to the memory we have stored! */
580 if( dwFlags
== DPSET_REMOTE
)
582 *lpdwDataSize
= This
->sp
->dwSpRemoteDataSize
;
583 *lplpData
= This
->sp
->lpSpRemoteData
;
585 if( This
->sp
->lpSpRemoteData
== NULL
)
590 else if( dwFlags
== DPSET_LOCAL
)
592 *lpdwDataSize
= This
->sp
->dwSpLocalDataSize
;
593 *lplpData
= This
->sp
->lpSpLocalData
;
595 if( This
->sp
->lpSpLocalData
== NULL
)
604 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
605 ( LPDIRECTPLAYSP iface
,
613 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
615 /* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
616 TRACE( "(%p)->(%p,%d,0x%08x)\n",
617 This
, lpData
, dwDataSize
, dwFlags
);
620 /* This is what the documentation says... */
621 if( dwFlags
!= DPSET_REMOTE
)
623 return DPERR_INVALIDPARAMS
;
626 /* ... but most service providers call this with 1 */
627 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
630 if( dwFlags
!= DPSET_REMOTE
)
632 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags
);
636 lpSpData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwDataSize
);
637 CopyMemory( lpSpData
, lpData
, dwDataSize
);
639 /* If we have data already allocated, free it and replace it */
640 if( dwFlags
== DPSET_REMOTE
)
642 HeapFree( GetProcessHeap(), 0, This
->sp
->lpSpRemoteData
);
643 This
->sp
->dwSpRemoteDataSize
= dwDataSize
;
644 This
->sp
->lpSpRemoteData
= lpSpData
;
646 else if ( dwFlags
== DPSET_LOCAL
)
648 HeapFree( GetProcessHeap(), 0, This
->sp
->lpSpLocalData
);
649 This
->sp
->lpSpLocalData
= lpSpData
;
650 This
->sp
->dwSpLocalDataSize
= dwDataSize
;
656 static VOID WINAPI IDirectPlaySPImpl_SendComplete
657 ( LPDIRECTPLAYSP iface
,
662 IDirectPlaySPImpl
*This
= (IDirectPlaySPImpl
*)iface
;
664 FIXME( "(%p)->(%p,0x%08x): stub\n",
665 This
, unknownA
, unknownB
);
668 static const IDirectPlaySPVtbl directPlaySPVT
=
675 IDirectPlaySPImpl_AddMRUEntry
,
676 IDirectPlaySPImpl_CreateAddress
,
677 IDirectPlaySPImpl_EnumAddress
,
678 IDirectPlaySPImpl_EnumMRUEntries
,
679 IDirectPlaySPImpl_GetPlayerFlags
,
680 IDirectPlaySPImpl_GetSPPlayerData
,
681 IDirectPlaySPImpl_HandleMessage
,
682 IDirectPlaySPImpl_SetSPPlayerData
,
683 IDirectPlaySPImpl_CreateCompoundAddress
,
684 IDirectPlaySPImpl_GetSPData
,
685 IDirectPlaySPImpl_SetSPData
,
686 IDirectPlaySPImpl_SendComplete
690 /* DP external interfaces to call into DPSP interface */
692 /* Allocate the structure */
693 LPVOID
DPSP_CreateSPPlayerData(void)
695 TRACE( "Creating SPPlayer data struct\n" );
696 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
697 sizeof( DP_SPPLAYERDATA
) );