/******************************************************************************* * DTBase.cpp * *------------* * Description: * This module contains the CDXBaseNTo1 transform *------------------------------------------------------------------------------- * Created By: Edward W. Connell Date: 07/28/97 * Copyright (C) 1997 Microsoft Corporation * All Rights Reserved * *------------------------------------------------------------------------------- * Revisions: * *******************************************************************************/ //--- Additional includes #include #include "DTBase.h" #include "new.h" //--- Initialize static member of debug scope class #ifdef _DEBUG CDXTDbgFlags CDXTDbgScope::m_DebugFlags; #endif //--- This should only be used locally in this file. We duplicated this GUID // value to avoid having to include DDraw. static const IID IID_IDXDupDirectDraw = { 0x6C14DB80,0xA733,0x11CE, { 0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 } }; static const IID IID_IDXDupDDrawSurface = { 0x6C14DB81,0xA733,0x11CE, { 0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 } }; static const IID IID_IDXDupDirect3DRM = {0x2bc49361, 0x8327, 0x11cf, {0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1 } }; static const IID IID_IDXDupDirect3DRM3 = {0x4516ec83, 0x8f20, 0x11d0, {0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3 } }; static const IID IID_IDXDupDirect3DRMMeshBuilder3 = { 0x4516ec82, 0x8f20, 0x11d0, { 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3} }; HRESULT CDXDataPtr::Assign(BOOL bMesh, IUnknown * pObject, IDXSurfaceFactory *pSurfaceFactory) { HRESULT hr = S_OK; if (pObject) { IUnknown *pNative = NULL; if (!bMesh) { //--- Try to get a DX surface hr = pObject->QueryInterface( IID_IDXSurface, (void **)&pNative ); if( FAILED( hr ) ) { IDirectDrawSurface *pSurf; //--- Try to get a DDraw surface hr = pObject->QueryInterface( IID_IDXDupDDrawSurface, (void **)&pSurf ); if( SUCCEEDED( hr ) ) { //--- Create a DXSurface from the DDraw surface hr = pSurfaceFactory->CreateFromDDSurface( pSurf, NULL, 0, NULL, IID_IDXSurface, (void **)&pNative ); pSurf->Release(); } } } else // Must be a mesh builder { hr = pObject->QueryInterface(IID_IDXDupDirect3DRMMeshBuilder3, (void **)&pNative); } if (SUCCEEDED(hr)) { Release(); m_pNativeInterface = pNative; pObject->AddRef(); m_pUnkOriginalObject = pObject; if (SUCCEEDED(pNative->QueryInterface(IID_IDXBaseObject, (void **)&m_pBaseObj))) { m_pBaseObj->GetGenerationId(&m_dwLastDirtyGenId); m_dwLastDirtyGenId--; } if (!bMesh) { ((IDXSurface *)pNative)->GetPixelFormat(NULL, &m_SampleFormat); } } else { if (hr == E_NOINTERFACE) { hr = E_INVALIDARG; } } } else { Release(); } return hr; } /* CDXDataPtr::Assign */ bool CDXDataPtr::IsDirty(void) { if (m_pBaseObj) { DWORD dwOldId = m_dwLastDirtyGenId; m_pBaseObj->GetGenerationId(&m_dwLastDirtyGenId); return dwOldId != m_dwLastDirtyGenId; } else { return false; } } DWORD CDXDataPtr::GenerationId(void) { if (m_pBaseObj) { DWORD dwGenId; m_pBaseObj->GetGenerationId(&dwGenId); return dwGenId; } else { return 0; } } bool CDXDataPtr::UpdateGenerationId(void) { if (m_pBaseObj) { DWORD dwOldId = m_dwLastUpdGenId; m_pBaseObj->GetGenerationId(&m_dwLastUpdGenId); return dwOldId != m_dwLastUpdGenId; } else { return false; } } /* CDXDataPtr::UpdateGenerationId */ ULONG CDXDataPtr::ObjectSize(void) { ULONG ulSize = 0; if (m_pBaseObj) { m_pBaseObj->GetObjectSize(&ulSize); } return ulSize; } /***************************************************************************** * CDXBaseNTo1::CDXBaseNTo1 * *--------------------------* * Description: * Constructor *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ CDXBaseNTo1::CDXBaseNTo1() : m_aInputs(NULL), m_ulNumInputs(0), m_ulNumProcessors(1), // Default to one until task manager is set m_dwGenerationId(1), m_dwCleanGenId(0), m_Duration(1.0f), m_StepResolution(0.0f), m_Progress(0.0f), m_dwBltFlags(0), m_bPickDoneByBase(false), m_bInMultiThreadWorkProc(FALSE), m_fQuality(0.5f), // Default to normal quality. // Wait forever before timing out on a lock by default m_ulLockTimeOut(INFINITE), // // Override these flags if your object does not support one or more of these options. // Typically, 3-D effects should set this member to 0. // m_dwMiscFlags(DXTMF_BLEND_WITH_OUTPUT | DXTMF_DITHER_OUTPUT | DXTMF_BLEND_SUPPORTED | DXTMF_DITHER_SUPPORTED | DXTMF_BOUNDS_SUPPORTED | DXTMF_PLACEMENT_SUPPORTED), // // If your object has a different number of objects or a different number of // required objects than 1, simply set these members in the body of your // constructor or in FinalConstruct(). For every input that is > the number // required, that input will be reported as optional. // // If your transform takes 2 required inputs, set both to 2. // If your transform takes 2 optional inputs, set MaxInputs = 2, NumInRequired = 0 // If your transform takes 1 required and 2 optional inputs, // set MaxInputs = 2, NumInRequired = 1 // // For more complex combinations of optinal/required, you will need to override // the OnSetup method of this base class, and override the methods // GetInOutInfo // m_ulMaxInputs(1), m_ulNumInRequired(1), // // If the intputs or output types are not surfaces then set appropriate object type // m_dwOptionFlags(0), // Inputs and output are surfaces, don't have to be the same size m_ulMaxImageBands(DXB_MAX_IMAGE_BANDS), m_fIsSetup(false) { DXTDBG_FUNC( "CDXBaseNTo1::CDXBaseNTo1" ); // // Set event handles to NULL. // memset(m_aEvent, 0, sizeof(m_aEvent)); } /* CDXBaseNTo1::CDXBaseNTo1 */ /***************************************************************************** * CDXBaseNTo1::~CDXBaseNTo1 * *---------------------------* * Description: * Constructor *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ CDXBaseNTo1::~CDXBaseNTo1() { DXTDBG_FUNC( "CDXBaseNTo1::~CDXBaseNTo1" ); _ReleaseReferences(); delete[] m_aInputs; //--- Release event objects for(ULONG i = 0; i < DXB_MAX_IMAGE_BANDS; ++i ) { if( m_aEvent[i] ) ::CloseHandle( m_aEvent[i] ); } } /* CDXBaseNTo1::~CDXBaseNTo1 */ /***************************************************************************** * CDXBaseNTo1::_ReleaseRefernces * *--------------------------------* * Description: * Releases all references to input and output objects *----------------------------------------------------------------------------- * Created By: RAL *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ void CDXBaseNTo1::_ReleaseReferences() { //--- Release data objects if( m_aInputs ) { for( ULONG i = 0; i < m_ulNumInputs; ++i ) { m_aInputs[i].Release(); } } m_Output.Release(); m_fIsSetup = false; } /* CDXBaseNTo1::_ReleaseRefernces */ STDMETHODIMP CDXBaseNTo1::GetGenerationId(ULONG *pGenerationId) { DXTDBG_FUNC( "CDXBaseNTo1::GetGenerationId" ); if (DXIsBadWritePtr(pGenerationId, sizeof(*pGenerationId))) { return E_POINTER; } Lock(); OnUpdateGenerationId(); *pGenerationId = m_dwGenerationId; Unlock(); return S_OK; } STDMETHODIMP CDXBaseNTo1::IncrementGenerationId(BOOL bRefresh) { DXTDBG_FUNC( "CDXBaseNTo1::IncrementGenerationId" ); HRESULT hr = S_OK; Lock(); m_dwGenerationId++; if (bRefresh) { // // If we have any inputs or outputs, call Setup again to refresh all internal // knowledge about the surfaces (formats, height or width could change, etc.) // // Note that we need to AddRef the objects prior to calling Setup becuase the // DXTransform may be the only object holding a referec // ULONG cInputs = m_ulNumInputs; ULONG cOutputs = 0; IUnknown *pOutput = m_Output.m_pUnkOriginalObject; if (pOutput) { cOutputs = 1; pOutput->AddRef(); } IUnknown ** ppInputs = NULL; if (cInputs) { ppInputs = (IUnknown **)_alloca(m_ulNumInputs * sizeof(IUnknown *)); for (ULONG i = 0; i < cInputs; i++) { ppInputs[i] = m_aInputs[i].m_pUnkOriginalObject; if (ppInputs[i]) ppInputs[i]->AddRef(); } } if (cInputs || cOutputs) // If we're not setup, skip this step. { hr = Setup(ppInputs, cInputs, &pOutput, cOutputs, 0); if (pOutput) pOutput->Release(); for (ULONG i = 0; i < cInputs; i++) { if (ppInputs[i]) ppInputs[i]->Release(); } } } Unlock(); return hr; } STDMETHODIMP CDXBaseNTo1::GetObjectSize(ULONG *pcbSize) { DXTDBG_FUNC( "CDXBaseNTo1::GetObjectSize" ); HRESULT hr = S_OK; if (DXIsBadWritePtr(pcbSize, sizeof(*pcbSize))) { hr = E_POINTER; } else { Lock(); *pcbSize = OnGetObjectSize(); Unlock(); } return hr; } void CDXBaseNTo1::_ReleaseServices(void) { m_cpTransFact.Release(); m_cpSurfFact.Release(); m_cpTaskMgr.Release(); m_cpDirectDraw.Release(); m_cpDirect3DRM.Release(); } // // The documentation for SetSite indicates that it is invaid to return // an error from this function, even if the site does not support the // functionality we want. So, even if there is no service provider, or // the required services are not available, we will return S_OK. // STDMETHODIMP CDXBaseNTo1::SetSite(IUnknown * pUnkSite) { DXTDBG_FUNC( "CDXBaseNTo1::SetSite" ); HRESULT hr = S_OK; Lock(); m_cpUnkSite = pUnkSite; _ReleaseServices(); if (pUnkSite) { if (DXIsBadInterfacePtr(pUnkSite)) { hr = E_INVALIDARG; } else { HRESULT hr2; hr2 = pUnkSite->QueryInterface(IID_IDXTransformFactory, (void **)&m_cpTransFact); if (SUCCEEDED(hr2)) { // // Allocate memory for inputs if necessary // if (m_aInputs == NULL && m_ulMaxInputs) { m_aInputs = new CDXDataPtr[m_ulMaxInputs]; if (!m_aInputs) { _ASSERT(TRUE); hr2 = E_OUTOFMEMORY; } } hr2 = m_cpTransFact->QueryService( SID_SDXSurfaceFactory, IID_IDXSurfaceFactory, (void **)&m_cpSurfFact); if (SUCCEEDED(hr2)) { hr2 = m_cpTransFact->QueryService( SID_SDXTaskManager, IID_IDXTaskManager, (void **)&m_cpTaskMgr); } if (SUCCEEDED(hr2)) { m_cpTaskMgr->QueryNumProcessors(&m_ulNumProcessors); if (m_ulMaxImageBands && (m_dwOptionFlags & (DXBOF_INPUTS_MESHBUILDER | DXBOF_OUTPUT_MESHBUILDER)) == 0) { for (ULONG i = 0; SUCCEEDED(hr2) && i < m_ulMaxImageBands; i++) { // // In theory we could get back here after failing to create an event, or // by getting a new site, so make sure it's non-null before creating one. // if (m_aEvent[i] == NULL) { m_aEvent[i] = ::CreateEvent(NULL, true, false, NULL); if (m_aEvent[i] == NULL) { hr2 = E_OUTOFMEMORY; } } } } } if (SUCCEEDED(hr2)) { hr2 = m_cpTransFact->QueryService(SID_SDirectDraw, IID_IDXDupDirectDraw, (void**)&m_cpDirectDraw); } if (SUCCEEDED(hr2) && (m_dwOptionFlags & (DXBOF_INPUTS_MESHBUILDER | DXBOF_OUTPUT_MESHBUILDER))) { hr2 = m_cpTransFact->QueryService(SID_SDirect3DRM, IID_IDXDupDirect3DRM3, (void **)&m_cpDirect3DRM); } if (FAILED(hr2)) { _ASSERT(TRUE); _ReleaseServices(); } } } } Unlock(); return hr; } STDMETHODIMP CDXBaseNTo1::GetSite(REFIID riid, void **ppv) { DXTDBG_FUNC( "CDXBaseNTo1::GetSite" ); HRESULT hr = S_OK; if( DXIsBadWritePtr(ppv, sizeof(*ppv)) ) { hr = E_POINTER; } else { Lock(); if (m_cpUnkSite) { hr = m_cpUnkSite->QueryInterface(riid, ppv); } else { *ppv = NULL; hr = E_FAIL; // This is the proper documented return code // for this interface if no service provider. } Unlock(); } return hr; } void CDXBaseNTo1::_UpdateBltFlags(void) { m_dwBltFlags = 0; if ((m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER) == 0) { if (m_dwMiscFlags & DXTMF_BLEND_WITH_OUTPUT) { if ((m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER) || m_ulNumInputs == 0) { m_dwBltFlags |= DXBOF_DO_OVER; } else { for(ULONG i = 0; i < m_ulNumInputs; ++i ) { if (InputSampleFormat(i) & DXPF_TRANSPARENCY) { m_dwBltFlags |= DXBOF_DO_OVER; break; } } } } // // Set the dither flag to true only if output error is > at least one input // if (m_dwMiscFlags & DXTMF_DITHER_OUTPUT) { ULONG OutputErr = (OutputSampleFormat() & DXPF_ERRORMASK); if (OutputErr) { if (m_ulNumInputs) { for(ULONG i = 0; i < m_ulNumInputs; ++i ) { if (InputSurface(i) && (ULONG)(InputSampleFormat(i) & DXPF_ERRORMASK) < OutputErr) { m_dwBltFlags |= DXBOF_DITHER; break; } } } else { // // If output has no error then don't set dither in blt flags // if (OutputErr) { m_dwBltFlags |= DXBOF_DITHER; } } } } } } /***************************************************************************** * CDXBaseNTo1::Setup * *--------------------* * Description: * The Setup method is used to perform any required one-time setup * before the Execute method is called. Single surfaces or SurfaceSets may * be used as arguments in any combination. * If punkOutputs is NULL, Execute will allocate an output result of the * appropriate size and return it. * if punkInputs and punkOutputs are NULL and it is a quick setup, the current * input and output objects are released. *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::Setup( IUnknown * const * punkInputs, ULONG ulNumInputs, IUnknown * const * punkOutputs, ULONG ulNumOutputs, DWORD dwFlags ) { DXTDBG_FUNC( "CDXBaseNTo1::Setup" ); //--- Lock object so state cannot change during setup DXAUTO_OBJ_LOCK HRESULT hr = S_OK; ULONG i; // // Early out for null setup. Forget about all other param validation, just do it. // if (ulNumInputs == 0 && ulNumOutputs == 0) { _ReleaseReferences(); OnReleaseObjects(); return hr; } //--- Validate Params //--- Make sure we have a reference to the transform factory if( !m_cpTransFact ) { hr = DXTERR_UNINITIALIZED; DXTDBG_MSG0( _CRT_ERROR, "\nTransform has not been initialized" ); } else { // // We know that if we have a transform factory that we must also have // allocated m_aInputs since this is done on SetSite to avoid work during // each setup. // _ASSERT(m_aInputs || m_ulMaxInputs == 0); if( dwFlags || // No flags are valid ulNumOutputs != 1 || ulNumInputs < m_ulNumInRequired || ulNumInputs > m_ulMaxInputs || (ulNumInputs && DXIsBadReadPtr( punkInputs , sizeof( *punkInputs ) * ulNumInputs )) || DXIsBadReadPtr(punkOutputs, sizeof(*punkOutputs)) || DXIsBadInterfacePtr(punkOutputs[0])) { hr = E_INVALIDARG; DXTDBG_MSG0( _CRT_ERROR, "\nTransform setup with invalid args" ); } else { for( i = 0; i < ulNumInputs; ++i ) { if((punkInputs[i] && DXIsBadInterfacePtr(punkInputs[i])) || (punkInputs[i] == NULL && i < m_ulNumInRequired)) { hr = E_INVALIDARG; DXTDBG_MSG0( _CRT_ERROR, "\nTransform setup with invalid args" ); break; } } } } //--- Allocate slots for input data object pointers if( SUCCEEDED( hr ) ) { //--- Release data objects _ReleaseReferences(); m_ulNumInputs = ulNumInputs; } // // Assign // for( i = 0; SUCCEEDED(hr) && i < m_ulNumInputs; ++i ) { hr = m_aInputs[i].Assign((m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER), punkInputs[i], m_cpSurfFact); } if( SUCCEEDED(hr) ) { hr = m_Output.Assign((m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER), punkOutputs[0], m_cpSurfFact); } if (SUCCEEDED(hr) && (m_dwOptionFlags & DXBOF_SAME_SIZE_INPUTS)) { hr = _MakeInputsSameSize(); } if (SUCCEEDED(hr)) { _UpdateBltFlags(); // Do this before calling OnSetup... hr = OnSetup(dwFlags); } if (FAILED(hr)) { _ReleaseReferences(); OnReleaseObjects(); DXTDBG_MSG0( _CRT_ERROR, "\nTransform setup failed" ); } else { m_fIsSetup = true; } return hr; } /* CDXBaseNTo1::Setup */ /***************************************************************************** * CDXBaseNTo1::_MakeInputsSameSize * *----------------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 03/31/98 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ HRESULT CDXBaseNTo1::_MakeInputsSameSize(void) { _ASSERT((m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER) == 0); HRESULT hr = S_OK; if (m_ulNumInputs > 1) // No need to do this for just one input! { CDXDBnds SurfBnds(false); CDXDBnds Union(true); ULONG i; for (i = 0; SUCCEEDED(hr) && i < m_ulNumInputs; i++) { if (InputSurface(i)) { hr = SurfBnds.SetToSurfaceBounds(InputSurface(i)); Union |= SurfBnds; } } for (i = 0; SUCCEEDED(hr) && i < m_ulNumInputs; i++) { if (InputSurface(i)) { hr = SurfBnds.SetToSurfaceBounds(InputSurface(i)); if (SUCCEEDED(hr) && SurfBnds != Union) { IDXSurfaceModifier *pSurfMod; hr = ::CoCreateInstance(CLSID_DXSurfaceModifier, NULL, CLSCTX_INPROC, IID_IDXSurfaceModifier, (void **)&pSurfMod); if (SUCCEEDED(hr)) { POINT p; p.x = p.y = 0; if (m_dwOptionFlags & DXBOF_CENTER_INPUTS) { p.x = (Union.Width() - SurfBnds.Width()) / 2; p.y = (Union.Height() - SurfBnds.Height()) / 2; } pSurfMod->SetForeground(InputSurface(i), FALSE, &p); pSurfMod->SetBounds(&Union); InputSurface(i)->Release(); pSurfMod->QueryInterface(IID_IDXSurface, (void **)&(m_aInputs[i].m_pNativeInterface)); ((IDXSurface *)m_aInputs[i].m_pNativeInterface)->GetPixelFormat(NULL, &m_aInputs[i].m_SampleFormat); pSurfMod->Release(); } } } } } return hr; } /***************************************************************************** * CDXBaseNTo1::Execute * *----------------------* * Description: * The Execute method is used to walk the inputs/outputs and break up the * work into suitably sized pieces to spread symetrically accross the available * processors in the system. *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1:: Execute( const GUID* pRequestID, const DXBNDS *pClipBnds, const DXVEC *pPlacement ) { DXTDBG_FUNC( "CDXBaseNTo1::Execute" ); //--- Lock object so state cannot change during execution DXAUTO_OBJ_LOCK HRESULT hr = S_OK; //--- Check args if( !HaveOutput() ) { DXTDBG_MSG0( _CRT_ERROR, "\nTransform has not been initialized" ); return DXTERR_UNINITIALIZED; } if (m_ulMaxImageBands == 0 || (m_dwOptionFlags & (DXBOF_INPUTS_MESHBUILDER | DXBOF_OUTPUT_MESHBUILDER))) { if ((pClipBnds && (m_dwMiscFlags & DXTMF_BOUNDS_SUPPORTED) == 0) || (pPlacement && (m_dwMiscFlags & DXTMF_PLACEMENT_SUPPORTED) == 0) ) { DXTDBG_MSG0( _CRT_ERROR, "\nTransform setup with invalid args" ); return E_INVALIDARG; } return OnExecute( pRequestID, pClipBnds, pPlacement ); } //--- Banded image working variables CDXTWorkInfoNTo1 WI; if ((pClipBnds && pClipBnds->eType != DXBT_DISCRETE) || (pPlacement && pPlacement->eType != DXBT_DISCRETE)) { hr = E_INVALIDARG; DXTDBG_MSG0( _CRT_ERROR, "\nTransform setup with invalid args" ); } else { hr = MapBoundsIn2Out( NULL, 0, 0, &WI.DoBnds ); if( hr == S_OK ) { hr = WI.OutputBnds.SetToSurfaceBounds(OutputSurface()); if (hr == S_OK) { hr = DXClipToOutputWithPlacement(WI.DoBnds, (CDXDBnds *)pClipBnds, WI.OutputBnds, (CDXDVec *)pPlacement); } } } //--- Check for clipping early exit if( hr != S_OK ) { return hr; } //=== Process ==================================================== _ASSERT(m_ulMaxImageBands <= DXB_MAX_IMAGE_BANDS); ULONG ulNumBandsToDo = m_ulNumProcessors; if( ulNumBandsToDo > 1 ) { ulNumBandsToDo = 1 + ((WI.OutputBnds.Width() * WI.OutputBnds.Height()) / 0x1000); if (ulNumBandsToDo > m_ulMaxImageBands) { ulNumBandsToDo = m_ulMaxImageBands; } if (ulNumBandsToDo > m_ulNumProcessors) { ulNumBandsToDo = m_ulNumProcessors; } } hr = OnInitInstData(WI, ulNumBandsToDo); if( SUCCEEDED( hr ) ) { if (ulNumBandsToDo == 1 && pRequestID == NULL) { static BOOL bContinue = TRUE; hr = WorkProc(WI, &bContinue); } else { _ASSERT( ulNumBandsToDo <= DXB_MAX_IMAGE_BANDS ); _ASSERT( m_aEvent[ulNumBandsToDo-1] ); long lStartAtRow = WI.DoBnds[DXB_Y].Min; ULONG ulRowCount = WI.DoBnds[DXB_Y].Max - lStartAtRow; _ASSERT( ( ulRowCount / ulNumBandsToDo ) != 0 ); //--- Init the work info structures ULONG ulBand, RowsPerBand = ulRowCount / ulNumBandsToDo; CDXTWorkInfoNTo1 *WIArray = (CDXTWorkInfoNTo1*)alloca( sizeof(CDXTWorkInfoNTo1) * ulNumBandsToDo ); DWORD *TaskIDs = (DWORD*)alloca( sizeof(DWORD) * ulNumBandsToDo ); DXTMTASKINFO* TaskInfo = (DXTMTASKINFO*)alloca( sizeof( DXTMTASKINFO ) * ulNumBandsToDo ); //--- Build task info list WI.hr = S_OK; WI.pvThis = this; long Start = lStartAtRow; ULONG Count = RowsPerBand; long OutputYDelta = WI.OutputBnds[DXB_Y].Min - WI.DoBnds[DXB_Y].Min; for (ulBand = 0; ulBand < ulNumBandsToDo; ++ulBand) { memcpy(&WIArray[ulBand], &WI, sizeof(WI)); WIArray[ulBand].DoBnds[DXB_Y].Min = Start; WIArray[ulBand].OutputBnds[DXB_Y].Min = Start + OutputYDelta; // If this is the last band, make sure it includes the last row. if (ulBand == ulNumBandsToDo - 1) { WIArray[ulBand].DoBnds[DXB_Y].Max = WI.DoBnds[DXB_Y].Max; WIArray[ulBand].OutputBnds[DXB_Y].Max = WI.OutputBnds[DXB_Y].Max; } else // Not the last band. { WIArray[ulBand].DoBnds[DXB_Y].Max = Start + Count; WIArray[ulBand].OutputBnds[DXB_Y].Max = Start + Count + OutputYDelta; } TaskInfo[ulBand].pfnTaskProc = _TaskProc; TaskInfo[ulBand].pTaskData = &WIArray[ulBand]; TaskInfo[ulBand].pfnCompletionAPC = NULL; TaskInfo[ulBand].dwCompletionData = 0; TaskInfo[ulBand].pRequestID = pRequestID; // Advance. Start += Count; } // // Procedural surfaces (and perhaps some transforms) need to "know" that // they are in a multi-threaded work procedure to avoid deadlocks. Procedural // surfaces need to allow LockSurface to work WITHOUT taking the object // critical section. Other transforms may also want to know this information // to avoid deadlocks. // m_bInMultiThreadWorkProc = TRUE; //--- Schedule the work and wait for it to complete hr = m_cpTaskMgr->ScheduleTasks( TaskInfo, m_aEvent, TaskIDs, ulNumBandsToDo, m_ulLockTimeOut ); m_bInMultiThreadWorkProc = FALSE; //--- Check return codes from work info structures // return the first bad hr if any for( ulBand = 0; SUCCEEDED( hr ) && ( ulBand < ulNumBandsToDo ); ++ulBand ) { hr = WIArray[ulBand].hr; if( hr != S_OK ) break; } } OnFreeInstData( WI ); } #ifdef _DEBUG if( FAILED( hr ) ) DXTDBG_MSG1( _CRT_ERROR, "\nExecute failed. HR = %X", hr ); #endif return hr; } /* CDXBaseNTo1::Execute */ /***************************************************************************** * CDXBaseNTo1::_ImageMapIn2Out * *------------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 07/28/97 *****************************************************************************/ HRESULT CDXBaseNTo1::_ImageMapIn2Out( CDXDBnds & bnds, ULONG ulNumInBnds, const CDXDBnds * pInBounds ) { HRESULT hr = S_OK; if(ulNumInBnds) { for(ULONG i = 0; i < ulNumInBnds; ++i ) { bnds |= pInBounds[i]; } } else { for( ULONG i = 0; SUCCEEDED(hr) && i < m_ulNumInputs; ++i ) { if (InputSurface(i)) { CDXDBnds SurfBnds(InputSurface(i), hr); bnds |= SurfBnds; } } } if (SUCCEEDED(hr)) { hr = DetermineBnds(bnds); } return hr; } /* CDXBaseNTo1::_ImageMapIn2Out */ /***************************************************************************** * CDXBaseNTo1::_MeshMapIn2Out * *-----------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 07/28/97 *****************************************************************************/ HRESULT CDXBaseNTo1::_MeshMapIn2Out(CDXCBnds & bnds, ULONG ulNumInBnds, CDXCBnds * pInBounds) { HRESULT hr = S_OK; if (m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER) { if(ulNumInBnds) { for(ULONG i = 0; i < ulNumInBnds; ++i ) { bnds |= pInBounds[i]; } } else { for(ULONG i = 0; SUCCEEDED(hr) && i < m_ulNumInputs; ++i ) { if (InputMeshBuilder(i)) { CDXCBnds MeshBnds(InputMeshBuilder(i), hr); bnds |= MeshBnds; } } } } else { // Already done -> bnds[DXB_T].Min = 0.0f; bnds[DXB_X].Min = bnds[DXB_Y].Min = bnds[DXB_Z].Min = -1.0f; bnds[DXB_X].Max = bnds[DXB_Y].Max = bnds[DXB_Z].Max = bnds[DXB_T].Max = 1.0f; } // // Call the derived class to get the scale values. // if (SUCCEEDED(hr)) { // Increase the size just a bit so we won't have rounding errors // result in bounds that don't actually contain the result. const float fBndsIncrease = 0.0001F; float fTemp = bnds.Width() * fBndsIncrease; bnds[DXB_X].Min -= fTemp; bnds[DXB_X].Max += fTemp; fTemp = fBndsIncrease * bnds.Height(); bnds[DXB_Y].Min -= fTemp; bnds[DXB_Y].Max += fTemp; fTemp = fBndsIncrease * bnds.Depth(); bnds[DXB_Z].Min -= fTemp; bnds[DXB_Z].Max += fTemp; hr = DetermineBnds(bnds); } return hr; } /* CDXBaseNTo1::_MeshMapIn2Out */ /***************************************************************************** * CDXBaseNTo1::MapBoundsIn2Out * *------------------------------* * Description: * The MapBoundsIn2Out method is used to perform coordinate transformation * from the input to the output coordinate space. *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::MapBoundsIn2Out( const DXBNDS *pInBounds, ULONG ulNumInBnds, ULONG ulOutIndex, DXBNDS *pOutBounds ) { DXTDBG_FUNC( "CDXBaseNTo1::MapBoundsIn2Out" ); if((ulNumInBnds && DXIsBadReadPtr( pInBounds, ulNumInBnds * sizeof( *pInBounds ) )) || ulOutIndex) { return E_INVALIDARG; } if( DXIsBadWritePtr( pOutBounds, sizeof( *pOutBounds ) ) ) { return E_POINTER; } // // Set the bounds to empty and the appropriate type. // memset(pOutBounds, 0, sizeof(*pOutBounds)); _ASSERT(DXBT_DISCRETE == 0); if (m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER) { pOutBounds->eType = DXBT_CONTINUOUS; } // // Make sure all input bounds are of the correct type. // if( ulNumInBnds ) { DXBNDTYPE eType = (m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER) ? DXBT_CONTINUOUS : DXBT_DISCRETE; for (ULONG i = 0; i < ulNumInBnds; i++) { if (pInBounds[i].eType != eType) { return E_INVALIDARG; } } } // // Now do the appropriate mapping // if (m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER) { // // NOTE: In the case of non-mesh inputs, the inputs are discrete, but they will // be completely ignored by the function so it's OK to cast them to CDXCBnds // return _MeshMapIn2Out(*((CDXCBnds *)pOutBounds), ulNumInBnds, (CDXCBnds *)pInBounds); } else { return _ImageMapIn2Out(*(CDXDBnds *)pOutBounds, ulNumInBnds, (CDXDBnds *)pInBounds); } } /* CDXBaseNTo1::MapBoundsIn2Out */ /***************************************************************************** * CDXBaseNTo1::MapBoundsOut2In * *------------------------------* * Description: * The MapBoundsOut2In method is used to perform coordinate transformation * from the input to the output coordinate space. *----------------------------------------------------------------------------- * Created By: Ed Connell Date: 07/28/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1:: MapBoundsOut2In( ULONG ulOutIndex, const DXBNDS *pOutBounds, ULONG ulInIndex, DXBNDS *pInBounds ) { DXTDBG_FUNC( "CDXBaseNTo1::MapBoundsOut2In" ); HRESULT hr = S_OK; if (m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER) { hr = E_NOTIMPL; // This is pointless for meshes. } else if(ulInIndex >= m_ulMaxInputs || ulOutIndex || DXIsBadReadPtr( pOutBounds, sizeof( *pOutBounds ) ) ) { hr = E_INVALIDARG; } else if( DXIsBadWritePtr( pInBounds, sizeof( *pInBounds ) ) ) { hr = E_POINTER; } else { *pInBounds = *pOutBounds; } return hr; } /* CDXBaseNTo1::MapBoundsOut2In */ /***************************************************************************** * CDXBaseNTo1::SetMiscFlags * *---------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 10/30.97 *----------------------------------------------------------------------------- * Parameters: * bMiscFlags - New value to set *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::SetMiscFlags( DWORD dwMiscFlags ) { DXTDBG_FUNC( "CDXBaseNTo1::SetMiscFlags" ); HRESULT hr = S_OK; Lock(); WORD wOpts = (WORD)dwMiscFlags; // Ignore high word. Only set low word. if (((WORD)m_dwMiscFlags) != wOpts) { if ((wOpts & (~DXTMF_VALID_OPTIONS)) || ((wOpts & DXTMF_BLEND_WITH_OUTPUT) && (m_dwMiscFlags & DXTMF_BLEND_SUPPORTED) == 0) || ((wOpts & DXTMF_DITHER_OUTPUT) && (m_dwMiscFlags & DXTMF_DITHER_SUPPORTED) == 0)) { hr = E_INVALIDARG; } else { m_dwMiscFlags &= 0xFFFF0000; m_dwMiscFlags |= wOpts; _UpdateBltFlags(); m_dwGenerationId++; } } Unlock(); return hr; } /* CDXBaseNTo1::SetMiscFlags */ /***************************************************************************** * CDXBaseNTo1::GetMiscFlags * *----------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 10/30/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::GetMiscFlags( DWORD* pdwMiscFlags ) { if( DXIsBadWritePtr( pdwMiscFlags, sizeof( *pdwMiscFlags ) ) ) { return E_POINTER; } *pdwMiscFlags = m_dwMiscFlags; return S_OK; } /* CDXBaseNTo1::GetMiscFlags */ /***************************************************************************** * CDXBaseNTo1::SetQuality * *----------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 10/30/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::SetQuality(float fQuality) { if ((m_dwMiscFlags & DXTMF_QUALITY_SUPPORTED) == 0) { return E_NOTIMPL; } if (fQuality < 0.0f || fQuality > 1.0f) { return E_INVALIDARG; } Lock(); if (m_fQuality != fQuality) { m_fQuality = fQuality; m_dwGenerationId++; } Unlock(); return S_OK; } /***************************************************************************** * CDXBaseNTo1::GetQuality * *-------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 10/30/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::GetQuality(float *pfQuality) { HRESULT hr = S_OK; if ((m_dwMiscFlags & DXTMF_QUALITY_SUPPORTED) == 0) { hr = E_NOTIMPL; } else { if( DXIsBadWritePtr( pfQuality, sizeof( *pfQuality ) ) ) { hr = E_POINTER; } else { *pfQuality = m_fQuality; } } return hr; } /***************************************************************************** * GetInOutInfo *----------------------------------------------------------------------------- * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::GetInOutInfo( BOOL bOutput, ULONG ulIndex, DWORD *pdwFlags, GUID * pIDs, ULONG *pcIDs, IUnknown **ppUnkCurObj ) { DXTDBG_FUNC( "CDXBaseNTo1::GetInOutInfo" ); HRESULT hr = S_FALSE; DWORD dwFlags = 0; BOOL bImage; if( bOutput ) { bImage = !(m_dwOptionFlags & DXBOF_OUTPUT_MESHBUILDER); if (ulIndex == 0) { hr = S_OK; } } else { bImage = !(m_dwOptionFlags & DXBOF_INPUTS_MESHBUILDER); if (ulIndex < m_ulMaxInputs) { hr = S_OK; if (ulIndex >= m_ulNumInRequired) { dwFlags = DXINOUTF_OPTIONAL; } } } if( hr == S_OK ) { if( pdwFlags && !DXIsBadWritePtr( pdwFlags, sizeof( *pdwFlags ) ) ) { *pdwFlags = dwFlags; } if( pIDs ) { if( DXIsBadWritePtr( pcIDs, sizeof( *pcIDs ) ) || DXIsBadWritePtr( pIDs, *pcIDs * sizeof( *pIDs ) ) ) { hr = E_INVALIDARG; } else { if (bImage) { if (*pcIDs > 0) { pIDs[0] = IID_IDXSurface; } if (*pcIDs > 1) { pIDs[1] = IID_IDXDupDDrawSurface; } else { hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA); } *pcIDs = 2; } else { if (*pcIDs > 0) { pIDs[0] = IID_IDXDupDirect3DRMMeshBuilder3; } else { hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA); } *pcIDs = 1; } } } else if( pcIDs ) { if( DXIsBadWritePtr( pcIDs, sizeof( *pcIDs ) ) ) { hr = E_POINTER; } else { *pcIDs = bImage ? 2 : 1; } } if (hr == S_OK && ppUnkCurObj) { if (DXIsBadWritePtr(ppUnkCurObj, sizeof(*ppUnkCurObj))) { hr = E_POINTER; } else { if (bOutput) { *ppUnkCurObj = m_Output.m_pNativeInterface; } else { *ppUnkCurObj = NULL; if (ulIndex < GetNumInputs()) { *ppUnkCurObj = m_aInputs[ulIndex].m_pUnkOriginalObject; } } if (*ppUnkCurObj) { (*ppUnkCurObj)->AddRef(); } } } } return hr; } /* CDXBaseNTo1::GetInOutInfo */ /***************************************************************************** * CDXBaseNTo1::OnUpdateGenerationId * *-----------------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ void CDXBaseNTo1::OnUpdateGenerationId(void) { DXTDBG_FUNC( "CDXBaseNTo1::OnUpdateGenerationId" ); if( (m_dwMiscFlags & DXTMF_INPLACE_OPERATION) && m_Output.UpdateGenerationId()) { m_dwGenerationId++; } for (ULONG i = 0; i < m_ulNumInputs; i++) { if (m_aInputs[i].UpdateGenerationId()) { m_dwGenerationId++; } } } /* CDXBaseNTo1::OnUpdateGenerationId */ /***************************************************************************** * CDXBaseNTo1::OnGetObjectSize * *------------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ ULONG CDXBaseNTo1::OnGetObjectSize(void) { return sizeof(*this); } // // Effect interface // /***************************************************************************** * CDXBaseNTo1::get_Progress * *---------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::get_Progress(float *pVal) { DXTDBG_FUNC( "CDXBaseNTo1::get_Progress" ); HRESULT hr = S_OK; if( DXIsBadWritePtr(pVal, sizeof(*pVal)) ) { hr = E_POINTER; } else { *pVal = m_Progress; } return hr; } /***************************************************************************** * CDXBaseNTo1::put_Progress * *---------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::put_Progress(float newVal) { DXTDBG_FUNC( "CDXBaseNTo1::put_Progress" ); HRESULT hr = S_OK; if (newVal < 0.0 || newVal > 1.0f) { hr = E_INVALIDARG; } else { Lock(); m_Progress = newVal; m_dwCleanGenId++; // This should not make the transform "dirty" internally m_dwGenerationId++; Unlock(); } return hr; } /***************************************************************************** * CDXBaseNTo1::get_StepResolution * *---------------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::get_StepResolution(float *pVal) { DXTDBG_FUNC( "CDXBaseNTo1::get_StepResolution" ); HRESULT hr = S_OK; if( DXIsBadWritePtr(pVal, sizeof(*pVal)) ) { hr = E_POINTER; } else { *pVal = m_StepResolution; } return hr; } /***************************************************************************** * CDXBaseNTo1::get_Duration * *---------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::get_Duration(float *pVal) { DXTDBG_FUNC( "CDXBaseNTo1::get_Duration" ); if( DXIsBadWritePtr(pVal, sizeof(*pVal)) ) { return E_POINTER; } else { *pVal = m_Duration; } return S_OK; } /***************************************************************************** * CDXBaseNTo1::put_Duration * *---------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::put_Duration(float newVal) { DXTDBG_FUNC( "CDXBaseNTo1::put_Duration" ); if (newVal <= 0.) { return E_INVALIDARG; } if(newVal != m_Duration) { Lock(); m_dwGenerationId++; m_dwCleanGenId++; // This should not make the transform "dirty" internally m_Duration = newVal; Unlock(); } return S_OK; } /***************************************************************************** * CDXBaseNTo1::PointPick * *------------------------* * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 5/5/98 *****************************************************************************/ STDMETHODIMP CDXBaseNTo1::PointPick(const DXVEC *pPoint, ULONG * pulInputSurfaceIndex, DXVEC *pInputPoint) { HRESULT hr = S_OK; BOOL bFoundIt = FALSE; // If we haven't been set up yet, we will just act as if we're transparent. if (!m_fIsSetup) { hr = S_FALSE; goto done; } if (DXIsBadReadPtr(pPoint, sizeof(*pPoint)) || pPoint->eType != DXBT_DISCRETE) { hr = E_INVALIDARG; } else { if (DXIsBadWritePtr(pulInputSurfaceIndex, sizeof(*pulInputSurfaceIndex)) || DXIsBadWritePtr(pInputPoint, sizeof(*pInputPoint))) { hr = E_POINTER; } else { HRESULT hr2 = S_OK; CDXDBnds bndsOutput; CDXDBnds OutBndsPoint(*((CDXDVec *)pPoint)); CDXDVec & InVec = *(new(pInputPoint) CDXDVec(*((CDXDVec *)pPoint))); // Get the output size of the DXTransform. If this point is not on // the output at all, we can return S_FALSE right now. hr = MapBoundsIn2Out(NULL, 0, 0, &bndsOutput); if (FAILED(hr)) { goto done; } if (!bndsOutput.TestIntersect(OutBndsPoint)) { hr = S_FALSE; goto done; } hr2 = OnSurfacePick(OutBndsPoint, *pulInputSurfaceIndex, InVec); if (hr2 != E_NOTIMPL) { hr = hr2; } else { //--- The derived class does not implement so we will do // the hit test against the input for them. ULONG * aulInIndex = (ULONG *)_alloca(sizeof(ULONG) * m_ulMaxInputs); BYTE * aWeights = (BYTE *)_alloca(sizeof(BYTE) * m_ulMaxInputs); ULONG ulNumToTest; OnGetSurfacePickOrder(OutBndsPoint, ulNumToTest, aulInIndex, aWeights); if( m_bPickDoneByBase && ( m_ulNumInputs > 1 ) ) { //--- We don't know how to do multi-input picking from the base. hr = E_NOTIMPL; } for (ULONG i = 0; SUCCEEDED(hr) && i < ulNumToTest; i++) { ULONG ulInput = aulInIndex[i]; if (HaveInput(ulInput) && aWeights[i]) { CDXDBnds Out2InBnds(false); hr = MapBoundsOut2In(0, &OutBndsPoint, ulInput, &Out2InBnds); if (SUCCEEDED(hr)) { CDXDBnds InSurfBnds(InputSurface(ulInput), hr); if (SUCCEEDED(hr) && InSurfBnds.IntersectBounds(Out2InBnds)) { IDXARGBReadPtr * pPtr; hr = InputSurface(ulInput)->LockSurface(&InSurfBnds, m_ulLockTimeOut, DXLOCKF_READ, IID_IDXARGBReadPtr, (void **)&pPtr, NULL); if( SUCCEEDED(hr) ) { DXPMSAMPLE val; pPtr->UnpackPremult(&val, 1, FALSE); pPtr->Release(); if (val.Alpha * aWeights[i] / 255) { InSurfBnds.GetMinVector(InVec); bFoundIt = TRUE; *pulInputSurfaceIndex = ulInput; break; } } } } } } if (SUCCEEDED(hr) & (!bFoundIt)) { hr = S_FALSE; } } } } done: return hr; } /* CDXBaseNTo1::PointPick */ /***************************************************************************** * RegisterTansform (STATIC member function) *----------------------------------------------------------------------------- * Description: *----------------------------------------------------------------------------- * Created By: RAL Date: 12/10/97 *----------------------------------------------------------------------------- * Parameters: *****************************************************************************/ HRESULT CDXBaseNTo1:: RegisterTransform(REFCLSID rcid, int ResourceId, ULONG cCatImpl, const CATID * pCatImpl, ULONG cCatReq, const CATID * pCatReq, BOOL bRegister) { DXTDBG_FUNC( "CDXBaseNTo1::RegisterTransform" ); HRESULT hr = bRegister ? _Module.UpdateRegistryFromResource(ResourceId, bRegister) : S_OK; if (SUCCEEDED(hr)) { CComPtr pCatRegister; HRESULT hr = ::CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC, IID_ICatRegister, (void **)&pCatRegister); if (SUCCEEDED(hr)) { if (bRegister) { hr = pCatRegister->RegisterClassImplCategories(rcid, cCatImpl, (CATID *)pCatImpl); if (SUCCEEDED(hr) && cCatReq && pCatReq) { hr = pCatRegister->RegisterClassReqCategories(rcid, cCatReq, (CATID *)pCatReq); } } else { pCatRegister->UnRegisterClassImplCategories(rcid, cCatImpl, (CATID *)pCatImpl); if (cCatReq && pCatReq) { pCatRegister->UnRegisterClassReqCategories(rcid, cCatReq, (CATID *)pCatReq); } } } } if ((!bRegister) && SUCCEEDED(hr)) { _Module.UpdateRegistryFromResource(ResourceId, bRegister); } return hr; } void CDXBaseNTo1::_TaskProc(void* pTaskInfo, BOOL* pbContinue ) { _ASSERT( pTaskInfo ); CDXTWorkInfoNTo1& WI = *((CDXTWorkInfoNTo1 *)pTaskInfo); CDXBaseNTo1& This = *((CDXBaseNTo1 *)WI.pvThis); WI.hr = This.WorkProc(WI, pbContinue); }