2 * Audio Renderer (CLSID_AudioRender)
5 * - implements IRefereneceClock.
6 * - implements seeking.
8 * hidenori@a2.ctktv.ne.jp
25 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(quartz);
28 #include "quartz_private.h"
33 static const WCHAR QUARTZ_AudioRender_Name[] =
34 { 'A','u','d','i','o',' ','R','e','n','d','e','r',0 };
35 static const WCHAR QUARTZ_AudioRenderPin_Name[] =
40 /***************************************************************************
42 * CAudioRendererImpl waveOut methods (internal)
47 HRESULT QUARTZ_HRESULT_From_MMRESULT( MMRESULT mr )
53 case MMSYSERR_NOERROR:
64 void CAudioRendererImpl_waveOutEventCallback(
65 HWAVEOUT hwo, UINT uMsg,
66 DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
68 CAudioRendererImpl* This = (CAudioRendererImpl*)dwInstance;
70 if ( uMsg == WOM_DONE )
71 SetEvent( This->m_hEventRender );
75 void CAudioRendererImpl_waveOutReset(
76 CAudioRendererImpl* This )
78 if ( !This->m_fWaveOutInit )
81 waveOutReset( This->m_hWaveOut );
82 SetEvent( This->m_hEventRender );
86 void CAudioRendererImpl_waveOutUninit(
87 CAudioRendererImpl* This )
93 if ( !This->m_fWaveOutInit )
96 waveOutReset( This->m_hWaveOut );
97 SetEvent( This->m_hEventRender );
99 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
101 if ( This->m_hdr[i].dwFlags & WHDR_PREPARED )
103 waveOutUnprepareHeader(
105 &This->m_hdr[i], sizeof(WAVEHDR) );
106 This->m_hdr[i].dwFlags = 0;
108 if ( This->m_hdr[i].lpData != NULL )
110 QUARTZ_FreeMem( This->m_hdr[i].lpData );
111 This->m_hdr[i].lpData = NULL;
115 waveOutClose( This->m_hWaveOut );
116 This->m_hWaveOut = (HWAVEOUT)NULL;
117 if ( This->m_hEventRender != (HANDLE)NULL )
119 CloseHandle( This->m_hEventRender );
120 This->m_hEventRender = (HANDLE)NULL;
123 This->m_fWaveOutInit = FALSE;
127 HRESULT CAudioRendererImpl_waveOutInit(
128 CAudioRendererImpl* This, WAVEFORMATEX* pwfx )
135 if ( This->m_fWaveOutInit )
140 if ( pwfx->nBlockAlign == 0 )
143 This->m_hEventRender = (HANDLE)NULL;
144 This->m_hWaveOut = (HWAVEOUT)NULL;
145 This->m_dwBlockSize = 0;
146 This->m_phdrCur = NULL;
147 ZeroMemory( &This->m_hdr, sizeof(This->m_hdr) );
151 &This->m_hWaveOut, WAVE_MAPPER, pwfx,
152 (DWORD)CAudioRendererImpl_waveOutEventCallback, (DWORD)This,
154 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
157 This->m_fWaveOutInit = TRUE;
159 This->m_hEventRender = CreateEventA(
160 NULL, TRUE, TRUE, NULL );
161 if ( This->m_hEventRender == (HANDLE)NULL )
167 dwBlockSize = pwfx->nAvgBytesPerSec / pwfx->nBlockAlign;
168 if ( dwBlockSize == 0 )
170 dwBlockSize *= pwfx->nBlockAlign;
171 This->m_dwBlockSize = dwBlockSize;
173 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
175 This->m_hdr[i].lpData = (CHAR*)QUARTZ_AllocMem( dwBlockSize );
176 if ( This->m_hdr[i].lpData == NULL )
181 mr = waveOutPrepareHeader(
183 &This->m_hdr[i], sizeof(WAVEHDR) );
184 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
187 This->m_hdr[i].dwFlags |= WHDR_DONE;
188 This->m_hdr[i].dwBufferLength = dwBlockSize;
189 This->m_hdr[i].dwUser = i;
194 CAudioRendererImpl_waveOutUninit(This);
198 static HRESULT CAudioRendererImpl_waveOutPause( CAudioRendererImpl* This )
200 if ( !This->m_fWaveOutInit )
203 return QUARTZ_HRESULT_From_MMRESULT( waveOutPause(
204 This->m_hWaveOut ) );
207 static HRESULT CAudioRendererImpl_waveOutRun( CAudioRendererImpl* This )
209 if ( !This->m_fWaveOutInit )
212 return QUARTZ_HRESULT_From_MMRESULT( waveOutRestart(
213 This->m_hWaveOut ) );
217 WAVEHDR* CAudioRendererImpl_waveOutGetBuffer(
218 CAudioRendererImpl* This )
222 if ( !This->m_fWaveOutInit )
225 if ( This->m_phdrCur != NULL )
226 return This->m_phdrCur;
228 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
230 if ( This->m_hdr[i].dwFlags & WHDR_DONE )
232 This->m_phdrCur = &(This->m_hdr[i]);
233 This->m_phdrCur->dwFlags &= ~WHDR_DONE;
234 This->m_phdrCur->dwBufferLength = 0;
235 return This->m_phdrCur;
243 HRESULT CAudioRendererImpl_waveOutWriteData(
244 CAudioRendererImpl* This,
245 const BYTE* pData, DWORD cbData, DWORD* pcbWritten )
251 if ( !This->m_fWaveOutInit )
257 if ( CAudioRendererImpl_waveOutGetBuffer(This) == NULL )
260 cbAvail = This->m_dwBlockSize - This->m_phdrCur->dwBufferLength;
261 if ( cbAvail > cbData )
263 memcpy( This->m_phdrCur->lpData, pData, cbAvail );
266 This->m_phdrCur->dwBufferLength += cbAvail;
268 *pcbWritten = cbAvail;
274 HRESULT CAudioRendererImpl_waveOutFlush(
275 CAudioRendererImpl* This )
280 if ( !This->m_fWaveOutInit )
282 if ( This->m_phdrCur == NULL )
285 if ( This->m_phdrCur->dwBufferLength == 0 )
290 This->m_phdrCur, sizeof(WAVEHDR) );
291 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
295 This->m_phdrCur = NULL;
300 HRESULT CAudioRendererImpl_waveOutGetVolume(
301 CAudioRendererImpl* This,
302 DWORD* pdwLeft, DWORD* pdwRight )
308 if ( !This->m_fWaveOutInit )
311 mr = waveOutGetVolume(
312 This->m_hWaveOut, &dwVol );
313 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
317 *pdwLeft = LOWORD(dwVol);
318 *pdwRight = HIWORD(dwVol);
324 HRESULT CAudioRendererImpl_waveOutSetVolume(
325 CAudioRendererImpl* This,
326 DWORD dwLeft, DWORD dwRight )
331 if ( !This->m_fWaveOutInit )
334 dwVol = dwLeft | (dwRight<<16);
336 mr = waveOutSetVolume(
337 This->m_hWaveOut, dwVol );
338 return QUARTZ_HRESULT_From_MMRESULT( mr );
341 /***************************************************************************
343 * CAudioRendererImpl methods
348 static HRESULT CAudioRendererImpl_OnActive( CBaseFilterImpl* pImpl )
350 CAudioRendererImpl_THIS(pImpl,basefilter);
353 FIXME( "(%p)\n", This );
355 if ( This->pPin->pin.pmtConn == NULL )
358 This->m_fInFlush = FALSE;
360 /* FIXME - don't work correctly.
361 hr = CAudioRendererImpl_waveOutRun(This);
369 static HRESULT CAudioRendererImpl_OnInactive( CBaseFilterImpl* pImpl )
371 CAudioRendererImpl_THIS(pImpl,basefilter);
375 FIXME( "(%p)\n", This );
377 if ( This->pPin->pin.pmtConn == NULL )
380 pwfx = (WAVEFORMATEX*)This->pPin->pin.pmtConn->pbFormat;
384 This->m_fInFlush = FALSE;
386 hr = CAudioRendererImpl_waveOutInit(This,pwfx);
390 /* FIXME - may cause deadlock.
391 hr = CAudioRendererImpl_waveOutPause(This);
399 static HRESULT CAudioRendererImpl_OnStop( CBaseFilterImpl* pImpl )
401 CAudioRendererImpl_THIS(pImpl,basefilter);
403 FIXME( "(%p)\n", This );
405 CAudioRendererImpl_waveOutUninit(This);
407 This->m_fInFlush = FALSE;
409 TRACE("returned\n" );
414 static const CBaseFilterHandlers filterhandlers =
416 CAudioRendererImpl_OnActive, /* pOnActive */
417 CAudioRendererImpl_OnInactive, /* pOnInactive */
418 CAudioRendererImpl_OnStop, /* pOnStop */
421 /***************************************************************************
423 * CAudioRendererPinImpl methods
427 static HRESULT CAudioRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
429 CAudioRendererPinImpl_THIS(pImpl,pin);
431 TRACE("(%p)\n",This);
433 if ( This->meminput.pAllocator != NULL )
435 IMemAllocator_Decommit(This->meminput.pAllocator);
436 IMemAllocator_Release(This->meminput.pAllocator);
437 This->meminput.pAllocator = NULL;
444 static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
446 CAudioRendererPinImpl_THIS(pImpl,pin);
447 const WAVEFORMATEX* pwfx;
449 TRACE("(%p,%p)\n",This,pmt);
451 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) )
453 TRACE("not audio\n");
456 if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_NULL ) &&
457 !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_PCM ) )
462 if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
468 TRACE("testing WAVE header\n");
470 if ( pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) )
473 pwfx = (const WAVEFORMATEX*)pmt->pbFormat;
476 if ( pwfx->wFormatTag != 1 )
479 TRACE("returned successfully.\n");
484 static HRESULT CAudioRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
486 CAudioRendererPinImpl_THIS(pImpl,pin);
492 FIXME( "(%p,%p)\n",This,pSample );
494 if ( !This->pRender->m_fWaveOutInit )
496 if ( This->pRender->m_fInFlush )
498 if ( pSample == NULL )
501 hr = IMediaSample_GetPointer( pSample, &pData );
504 dwDataLength = (DWORD)IMediaSample_GetActualDataLength( pSample );
508 TRACE("trying to write %lu bytes\n",dwDataLength);
510 ResetEvent( This->pRender->m_hEventRender );
511 hr = CAudioRendererImpl_waveOutWriteData(
512 This->pRender,pData,dwDataLength,&dwWritten);
517 WaitForSingleObject( This->pRender->m_hEventRender, INFINITE );
521 dwDataLength -= dwWritten;
522 hr = CAudioRendererImpl_waveOutFlush(This->pRender);
525 if ( dwDataLength == 0 )
532 static HRESULT CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
534 CAudioRendererPinImpl_THIS(pImpl,pin);
536 TRACE( "(%p)\n", This );
542 static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl )
544 CAudioRendererPinImpl_THIS(pImpl,pin);
546 FIXME( "(%p)\n", This );
548 This->pRender->m_fInFlush = FALSE;
550 /* FIXME - don't notify twice until stopped or seeked. */
551 return CBaseFilterImpl_MediaEventNotify(
552 &This->pRender->basefilter, EC_COMPLETE,
553 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
556 static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
558 CAudioRendererPinImpl_THIS(pImpl,pin);
560 FIXME( "(%p)\n", This );
562 This->pRender->m_fInFlush = TRUE;
563 CAudioRendererImpl_waveOutReset(This->pRender);
568 static HRESULT CAudioRendererPinImpl_EndFlush( CPinBaseImpl* pImpl )
570 CAudioRendererPinImpl_THIS(pImpl,pin);
572 FIXME( "(%p)\n", This );
574 This->pRender->m_fInFlush = FALSE;
579 static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
581 CAudioRendererPinImpl_THIS(pImpl,pin);
583 FIXME( "(%p)\n", This );
585 This->pRender->m_fInFlush = FALSE;
590 static const CBasePinHandlers pinhandlers =
592 NULL, /* pOnPreConnect */
593 NULL, /* pOnPostConnect */
594 CAudioRendererPinImpl_OnDisconnect, /* pOnDisconnect */
595 CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */
596 NULL, /* pQualityNotify */
597 CAudioRendererPinImpl_Receive, /* pReceive */
598 CAudioRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
599 CAudioRendererPinImpl_EndOfStream, /* pEndOfStream */
600 CAudioRendererPinImpl_BeginFlush, /* pBeginFlush */
601 CAudioRendererPinImpl_EndFlush, /* pEndFlush */
602 CAudioRendererPinImpl_NewSegment, /* pNewSegment */
606 /***************************************************************************
608 * new/delete CAudioRendererImpl
612 /* can I use offsetof safely? - FIXME? */
613 static QUARTZ_IFEntry FilterIFEntries[] =
615 { &IID_IPersist, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
616 { &IID_IMediaFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
617 { &IID_IBaseFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
618 { &IID_IBasicAudio, offsetof(CAudioRendererImpl,basaud)-offsetof(CAudioRendererImpl,unk) },
621 static HRESULT CAudioRendererImpl_OnQueryInterface(
622 IUnknown* punk, const IID* piid, void** ppobj )
624 CAudioRendererImpl_THIS(punk,unk);
626 if ( This->pSeekPass == NULL )
627 return E_NOINTERFACE;
629 if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
630 IsEqualGUID( &IID_IMediaSeeking, piid ) )
632 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
633 return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
636 return E_NOINTERFACE;
639 static void QUARTZ_DestroyAudioRenderer(IUnknown* punk)
641 CAudioRendererImpl_THIS(punk,unk);
643 TRACE( "(%p)\n", This );
645 if ( This->pPin != NULL )
647 IUnknown_Release(This->pPin->unk.punkControl);
650 if ( This->pSeekPass != NULL )
652 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
653 This->pSeekPass = NULL;
656 CAudioRendererImpl_UninitIBasicAudio(This);
657 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
660 HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj)
662 CAudioRendererImpl* This = NULL;
665 TRACE("(%p,%p)\n",punkOuter,ppobj);
667 This = (CAudioRendererImpl*)
668 QUARTZ_AllocObj( sizeof(CAudioRendererImpl) );
670 return E_OUTOFMEMORY;
671 This->pSeekPass = NULL;
673 This->m_fInFlush = FALSE;
674 This->m_fWaveOutInit = FALSE;
675 This->m_hEventRender = (HANDLE)NULL;
677 QUARTZ_IUnkInit( &This->unk, punkOuter );
678 This->qiext.pNext = NULL;
679 This->qiext.pOnQueryInterface = &CAudioRendererImpl_OnQueryInterface;
680 QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
682 hr = CBaseFilterImpl_InitIBaseFilter(
684 This->unk.punkControl,
686 QUARTZ_AudioRender_Name,
690 hr = CAudioRendererImpl_InitIBasicAudio(This);
693 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
699 QUARTZ_FreeObj(This);
703 This->unk.pEntries = FilterIFEntries;
704 This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
705 This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer;
707 hr = QUARTZ_CreateAudioRendererPin(
709 &This->basefilter.csFilter,
712 hr = QUARTZ_CompList_AddComp(
713 This->basefilter.pInPins,
714 (IUnknown*)&This->pPin->pin,
717 hr = QUARTZ_CreateSeekingPassThruInternal(
718 (IUnknown*)&(This->unk), &This->pSeekPass,
719 TRUE, (IPin*)&(This->pPin->pin) );
723 IUnknown_Release( This->unk.punkControl );
727 *ppobj = (void*)&(This->unk);
733 /***************************************************************************
735 * new/delete CAudioRendererPinImpl
739 /* can I use offsetof safely? - FIXME? */
740 static QUARTZ_IFEntry PinIFEntries[] =
742 { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) },
743 { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) },
746 static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk)
748 CAudioRendererPinImpl_THIS(punk,unk);
750 TRACE( "(%p)\n", This );
752 CPinBaseImpl_UninitIPin( &This->pin );
753 CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
756 HRESULT QUARTZ_CreateAudioRendererPin(
757 CAudioRendererImpl* pFilter,
758 CRITICAL_SECTION* pcsPin,
759 CAudioRendererPinImpl** ppPin)
761 CAudioRendererPinImpl* This = NULL;
764 TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
766 This = (CAudioRendererPinImpl*)
767 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) );
769 return E_OUTOFMEMORY;
771 QUARTZ_IUnkInit( &This->unk, NULL );
772 This->pRender = pFilter;
774 hr = CPinBaseImpl_InitIPin(
776 This->unk.punkControl,
778 &pFilter->basefilter,
779 QUARTZ_AudioRenderPin_Name,
785 hr = CMemInputPinBaseImpl_InitIMemInputPin(
787 This->unk.punkControl,
791 CPinBaseImpl_UninitIPin( &This->pin );
797 QUARTZ_FreeObj(This);
801 This->unk.pEntries = PinIFEntries;
802 This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
803 This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin;
807 TRACE("returned successfully.\n");
813 /***************************************************************************
815 * CAudioRendererImpl::IBasicAudio
819 static HRESULT WINAPI
820 IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj)
822 CAudioRendererImpl_THIS(iface,basaud);
824 TRACE("(%p)->()\n",This);
826 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
830 IBasicAudio_fnAddRef(IBasicAudio* iface)
832 CAudioRendererImpl_THIS(iface,basaud);
834 TRACE("(%p)->()\n",This);
836 return IUnknown_AddRef(This->unk.punkControl);
840 IBasicAudio_fnRelease(IBasicAudio* iface)
842 CAudioRendererImpl_THIS(iface,basaud);
844 TRACE("(%p)->()\n",This);
846 return IUnknown_Release(This->unk.punkControl);
849 static HRESULT WINAPI
850 IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo)
852 CAudioRendererImpl_THIS(iface,basaud);
854 FIXME("(%p)->()\n",This);
859 static HRESULT WINAPI
860 IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
862 CAudioRendererImpl_THIS(iface,basaud);
864 FIXME("(%p)->()\n",This);
869 static HRESULT WINAPI
870 IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
872 CAudioRendererImpl_THIS(iface,basaud);
874 FIXME("(%p)->()\n",This);
879 static HRESULT WINAPI
880 IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
882 CAudioRendererImpl_THIS(iface,basaud);
884 FIXME("(%p)->()\n",This);
890 static HRESULT WINAPI
891 IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol)
893 CAudioRendererImpl_THIS(iface,basaud);
895 FIXME("(%p)->()\n",This);
900 static HRESULT WINAPI
901 IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol)
903 CAudioRendererImpl_THIS(iface,basaud);
905 FIXME("(%p)->()\n",This);
910 static HRESULT WINAPI
911 IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance)
913 CAudioRendererImpl_THIS(iface,basaud);
915 FIXME("(%p)->()\n",This);
920 static HRESULT WINAPI
921 IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance)
923 CAudioRendererImpl_THIS(iface,basaud);
925 FIXME("(%p)->()\n",This);
931 static ICOM_VTABLE(IBasicAudio) ibasicaudio =
933 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
934 /* IUnknown fields */
935 IBasicAudio_fnQueryInterface,
936 IBasicAudio_fnAddRef,
937 IBasicAudio_fnRelease,
938 /* IDispatch fields */
939 IBasicAudio_fnGetTypeInfoCount,
940 IBasicAudio_fnGetTypeInfo,
941 IBasicAudio_fnGetIDsOfNames,
942 IBasicAudio_fnInvoke,
943 /* IBasicAudio fields */
944 IBasicAudio_fnput_Volume,
945 IBasicAudio_fnget_Volume,
946 IBasicAudio_fnput_Balance,
947 IBasicAudio_fnget_Balance,
951 HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This )
953 TRACE("(%p)\n",This);
954 ICOM_VTBL(&This->basaud) = &ibasicaudio;
959 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This )
961 TRACE("(%p)\n",This);