openDecal/Native/Inject/LayerSite.cpp
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:27:56 +01:00

992 lines
No EOL
24 KiB
C++

// BarSite.cpp : Implementation of cBarSite
#include "stdafx.h"
#include "Inject.h"
#include "LayerSite.h"
#include "Manager.h"
#include "Button.h"
#include "Pager.h"
/////////////////////////////////////////////////////////////////////////////
// cBarSite
enum eSinkCaps
{
eSinkCapRender = 0x01,
eSinkCapMouse = 0x02,
eSinkCapKeyboard = 0x04,
eSinkCapPopup = 0x08,
eSinkCapTimer = 0x10
};
cLayerSite::cLayerSite()
: m_pParent( NULL ),
m_dwSinkCaps( 0 ),
m_Alpha( 255 )
{
}
cLayerSite::~cLayerSite()
{
// Make sure we're really destroyed
_ASSERTE( m_pParent == NULL );
_ASSERTE( m_children.size() == 0 );
}
void cLayerSite::removeChild( cLayerSite *pChild )
{
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
{
if( *i == pChild )
{
m_children.erase( i );
break;
}
}
}
struct cSinkCapTest
{
eSinkCaps m_mask;
const IID *m_iid;
};
void cLayerSite::create( LayerParams *pParams, cLayerSite *pParent, ILayer *pSink )
{
// First copy all the relevant data
m_params = *pParams;
m_pParent = pParent;
static cSinkCapTest _capstest[] = {
{ eSinkCapRender, &IID_ILayerRender },
{ eSinkCapMouse, &IID_ILayerMouse },
{ eSinkCapKeyboard, &IID_ILayerKeyboard },
{ eSinkCapPopup, &IID_ILayerPopup },
{ eSinkCapTimer, &IID_ILayerTimer },
};
static cSinkCapTest *_end_caps = _capstest + ( sizeof( _capstest ) / sizeof( cSinkCapTest ) );
m_pSink = pSink;
// Probe for relevant interfaces
for( cSinkCapTest *i = _capstest; i != _end_caps; ++ i )
{
CComPtr< IUnknown > pUnk;
if( SUCCEEDED( pSink->QueryInterface( *( i->m_iid ), reinterpret_cast< void ** >( &pUnk ) ) ) )
m_dwSinkCaps |= i->m_mask;
}
// Do initialization activities
if( !( m_params.render & eRenderClipped ) )
{
// Create the back buffer
SIZE sz = { m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top };
if( sz.cx > 0 && sz.cy > 0 )
cManager::_p->CreateCanvas( &sz, &m_pBuffer );
}
// Add in the default render flags
// All layer begin their life transparent until set otherwise
m_params.render |= eRenderTransparent;
// Make this control format itself next round
Reformat();
Invalidate();
m_pSink->LayerCreate( this );
}
void cLayerSite::destroy()
{
// First destroy all of our children
while( !m_children.empty() )
{
#ifdef _DEBUG
int nChildren = m_children.size();
m_children.front()->destroy();
_ASSERTE( m_children.size() == ( nChildren - 1 ) );
#else
m_children.front()->destroy();
#endif
}
// Remove from parent
if( m_pParent != NULL )
{
m_pParent->removeChild( this );
m_pParent = NULL;
}
// The child now releases the reference - this should trick our reference count to 0
m_pSink->LayerDestroy();
// After LayerDestroy returns this object has already been deleted -
// do not touch any data members and we're OK
// Reset capture pointers
if( cManager::_p->m_pMouseDown == this )
cManager::_p->m_pMouseDown = NULL;
if( cManager::_p->m_pMouseOver == this )
cManager::_p->m_pMouseOver = NULL;
if( cManager::_p->m_pKeyboard == this )
cManager::_p->m_pKeyboard = NULL;
for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i )
{
if( *i == this )
{
cManager::_p->m_popups.erase( i );
break;
}
}
}
void cLayerSite::format()
{
// ::MessageBox( NULL, _T( "cLayerSite::format" ), _T( "Inject.dll" ), MB_OK );
// This is no longer recursive - in all cases, parents position their children
formatLayer();
}
void cLayerSite::formatLayer()
{
// Check for timers
if( m_timers.size() > 0 )
{
long nCurrentTime = ::timeGetTime();
for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); )
{
if( ( i->m_nLastTimeout + i->m_nInterval ) <= nCurrentTime )
{
// Default to false, prevent the assert from going off *lots*
VARIANT_BOOL bContinue = VARIANT_FALSE;
++ i->m_nRepetitions;
if( m_dwSinkCaps & eSinkCapTimer )
{
CComPtr< ILayerTimer > pTimer;
m_pSink->QueryInterface( &pTimer );
pTimer->TimerTimeout( i->m_nID, nCurrentTime - i->m_nLastTimeout, i->m_nRepetitions, &bContinue );
}
if( bContinue )
i->m_nLastTimeout = nCurrentTime;
else
{
// Do not continue timing
i = m_timers.erase( i );
continue;
}
}
++ i;
}
}
// When reformatting - never reformat a surface that's 0,0 size
if( ( m_params.render & eRenderReformatNext ) &&
m_params.pos.right > m_params.pos.left &&
m_params.pos.bottom > m_params.pos.top )
{
// Do a reformat - NOTE: it's done here becasue a reformat will almost
// always destroy the surface
if( m_dwSinkCaps & eSinkCapRender )
{
CComPtr< ILayerRender > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->Reformat();
}
// Clear the reformat flag
m_params.render &= ~eRenderReformatNext;
}
// Iterate over the children
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
( *i )->formatLayer();
}
void cLayerSite::prerender()
{
if( m_dwSinkCaps & eSinkCapRender )
{
CComPtr< ILayerRender > pRender;
m_pSink->QueryInterface( &pRender );
pRender->PreRender();
}
// Iterate over the children
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
( *i )->prerender();
}
void cLayerSite::render(ICanvas *pPrimary)
{
if( !( m_params.render & eRenderClipped ) )
{
// Check for 0,0 size
if( m_params.pos.right > m_params.pos.left && m_params.pos.bottom > m_params.pos.top )
{
// ::MessageBox( NULL, _T( "cLayerSite::render" ), _T( "Inject.dll" ), MB_OK );
_ASSERTE( m_pBuffer.p != NULL );
VARIANT_BOOL bRedraw;
m_pBuffer->get_WasLost( &bRedraw );
// Here we push a scratch clip rect for the entire area
// This is intended for unclipped layers that modfiy their
// child clipping area.
RECT rcAll = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top };
VARIANT_BOOL bDrawChildren;
m_pBuffer->PushClipRect( &rcAll, &bDrawChildren );
// Assuming this area is non-0 size
_ASSERTE( bDrawChildren );
renderBuffer( m_pBuffer, !!bRedraw );
m_pBuffer->PopClipRect();
// Place it on the screen
POINT pt = { m_params.pos.left, m_params.pos.top };
RECT rc = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top };
pPrimary->put_Alpha(m_Alpha);
pPrimary->Blt( &rc, m_pBuffer, &pt );
}
else
// This object has no size, it should have no canvas
_ASSERTE( m_pBuffer.p == NULL );
}
// Iterate through children - look for more non-clipped layers to render
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
( *i )->render( pPrimary );
}
void cLayerSite::renderBuffer( ICanvas *pBuffer, bool bForce )
{
// Remove the next flag
VARIANT_BOOL bRenderChildren = VARIANT_TRUE;
bool bRendered = bForce;
if( m_dwSinkCaps & eSinkCapRender )
{
CComPtr< ILayerRender > pLayer;
m_pSink->QueryInterface( &pLayer );
if( bForce || ( m_params.render & eRenderNext ) )
{
if( !( m_params.render & eRenderClipped ) )
{
RECT rcClient = { 0, 0, m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top };
// Unclipped layers all get an inital transparent fill
m_pBuffer->Fill( &rcClient, RGB( 0, 255, 255 ) );
}
bRendered = true;
pLayer->Render( pBuffer );
}
pLayer->AdjustRenderArea( pBuffer, &bRenderChildren );
}
m_params.render &= ~eRenderNext;
if( !bRenderChildren )
// While adjusting the render parameters, the rectangle got clipped out of existance
return;
// Walk through the children and transform the surface params
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
{
if( !( ( *i )->m_params.render & eRenderClipped ) )
// Only clipped children
continue;
// Clip the child rectangle
VARIANT_BOOL bRenderChild;
pBuffer->PushClipRect( &( *i )->m_params.pos, &bRenderChild );
if( bRenderChild )
// Iterate
( *i )->renderBuffer( pBuffer, bRendered );
pBuffer->PopClipRect();
}
}
void cLayerSite::reformat()
{
if( m_dwSinkCaps & eSinkCapRender )
// Schedule a reformat for next render cycle
m_params.render |= eRenderReformatNext;
// Propagate reformat to children
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
( *i )->reformat();
}
cLayerSite *cLayerSite::hitTestUnclipped( POINTS pt, ICanvas *pCanvas )
{
// First test if any children have been hit and delegate to them
// as children have a higher z-order value
cLayerSite *pSite;
for( cChildList::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++ i )
{
pSite = ( *i )->hitTestUnclipped( pt, pCanvas );
if( pSite != NULL )
// Found a child hit - overlapping children are not tested
// as there is no sibling clipping
return pSite;
}
// Children are not hit, check if we hit ourselves
if( !( m_params.render & eRenderClipped ) )
{
POINT ptl = { pt.x, pt.y };
VARIANT_BOOL bVisible;
pCanvas->PushClipRect( &m_params.pos, &bVisible );
cLayerSite *pHit = NULL;
if( bVisible )
{
VARIANT_BOOL bHit;
pCanvas->HitTest( &ptl, &bHit );
if( bHit )
{
// Check for transparent area hitting
if( ( m_dwSinkCaps & eSinkCapRender ) && ( m_params.render & eRenderTransparent ) )
{
// This may contain transparent areas
// TODO: Check for transparent areas
pHit = this;
}
else
pHit = this;
}
}
pCanvas->PopClipRect();
return pHit;
}
// Nothing hit in this branch
return NULL;
}
cLayerSite *cLayerSite::hitTestClipped( POINTS pt, LPPOINT pptHit, ICanvas *pCanvas )
{
// ::MessageBox( NULL, _T( "cLayerSite::hitTestClipped" ), _T( "Inject.dll" ), MB_OK );
// Convert the render params
VARIANT_BOOL bRenderChildren = VARIANT_TRUE;
if( m_dwSinkCaps & eSinkCapRender )
{
CComPtr< ILayerRender > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->AdjustRenderArea( pCanvas, &bRenderChildren );
}
POINT ptm = { pt.x, pt.y };
if( bRenderChildren )
{
for( cChildList::reverse_iterator i = m_children.rbegin(); i != m_children.rend(); ++ i )
{
if( !( ( *i )->m_params.render & eRenderClipped ) )
// Only clipped children
continue;
// Clip the child rectangle
VARIANT_BOOL bVisible;
pCanvas->PushClipRect( &( *i )->m_params.pos, &bVisible );
if( bVisible )
{
VARIANT_BOOL bHit;
pCanvas->HitTest( &ptm, &bHit );
if( bHit )
{
cLayerSite *pRet = ( *i )->hitTestClipped( pt, pptHit, pCanvas );
pCanvas->PopClipRect();
return pRet;
}
}
pCanvas->PopClipRect();
}
}
*pptHit = ptm;
pCanvas->ToClient( pptHit );
return this;
}
cLayerSite *cLayerSite::hitTest( POINTS pt, LPPOINT pptHit, ICanvas *pCanvas )
{
// First, find the unclipped parent
cLayerSite *pHitUnclipped = hitTestUnclipped( pt, pCanvas );
if( pHitUnclipped == NULL )
// Absolutely nothing hit
return NULL;
VARIANT_BOOL bVisible;
pCanvas->PushClipRect( &pHitUnclipped->m_params.pos, &bVisible );
cLayerSite *pHitClipped = pHitUnclipped->hitTestClipped( pt, pptHit, pCanvas );
pCanvas->PopClipRect();
return pHitClipped;
}
void cLayerSite::clipCanvas(ICanvas *pCanvas)
{
if( m_params.render & eRenderClipped )
m_pParent->clipCanvas( pCanvas );
VARIANT_BOOL bVisible;
pCanvas->PushClipRect( &m_params.pos, &bVisible );
if( m_dwSinkCaps & eSinkCapRender )
{
CComPtr< ILayerRender > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->AdjustRenderArea( pCanvas, &bVisible );
}
}
bool cLayerSite::isClippedChild( cLayerSite *pChild )
{
for( cLayerSite *pChildLayer = pChild; pChild != NULL; pChild = pChild->m_pParent )
{
if( pChildLayer == this )
return true;
if( !( pChildLayer->m_params.render & eRenderClipped ) )
break;
}
return false;
}
bool cLayerSite::isChild( cLayerSite *pChild )
{
for( cLayerSite *pChildLayer = pChild; pChildLayer != NULL; pChildLayer = pChildLayer->m_pParent )
{
if( pChildLayer == this )
return true;
}
return false;
}
cLayerSite *cLayerSite::getCommonClippedParent( cLayerSite *pHit )
{
for( cLayerSite *pCurrentParent = this; pCurrentParent != NULL; pCurrentParent = pCurrentParent->m_pParent )
{
for( cLayerSite *pHitParent = pHit; pHitParent != NULL; pHitParent = pHitParent->m_pParent )
{
if( pHitParent == pCurrentParent )
return pHitParent;
if( !( pCurrentParent->m_params.render & eRenderClipped ) )
break;
}
if( !( pCurrentParent->m_params.render & eRenderClipped ) )
break;
}
return NULL;
}
void cLayerSite::sendMouseEnter( cLayerSite *pCommonParent, MouseState *pMS )
{
if( pCommonParent != this && ( m_params.render & eRenderClipped ) )
// Enter our parent first - note that we stop at the unclipped parent
m_pParent->sendMouseEnter( pCommonParent, pMS );
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseEnter( pMS );
}
}
void cLayerSite::sendMouseExit( cLayerSite *pCommonParent, MouseState *pMS )
{
for( cLayerSite *pExit = this; pExit != pCommonParent; pExit = pExit->m_pParent )
{
if( !( pExit->m_params.render & eRenderClipped ) )
// Common parent may be set to NULL if we're switching
// to another unclipped parent
break;
if( pExit->m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
pExit->m_pSink->QueryInterface( &pLayer );
pLayer->MouseExit( pMS );
}
}
}
void cLayerSite::sendMouseDown( MouseState *pMS )
{
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseDown( pMS );
}
}
void cLayerSite::sendMouseUp( MouseState *pMS )
{
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseUp( pMS );
}
}
void cLayerSite::sendMouseMove( MouseState *pMS )
{
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseMove( pMS );
}
}
void cLayerSite::sendMouseDblClk( MouseState *pMS )
{
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseDblClk( pMS );
}
}
void cLayerSite::sendMouseEvent( long nMsg, long wParam, long lParam )
{
if( m_dwSinkCaps & eSinkCapMouse )
{
CComPtr< ILayerMouse > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->MouseEvent( nMsg, wParam, lParam );
}
}
void cLayerSite::sendKeyboardEndCapture( VARIANT_BOOL bCancel )
{
if( m_dwSinkCaps & eSinkCapKeyboard )
{
CComPtr< ILayerKeyboard > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->KeyboardEndCapture( bCancel );
}
}
void cLayerSite::sendKeyboardChar( KeyState *pKS )
{
if( m_dwSinkCaps & eSinkCapKeyboard )
{
CComPtr< ILayerKeyboard > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->KeyboardChar( pKS );
}
}
void cLayerSite::sendKeyboardEvent( long nMsg, long wParam, long lParam )
{
if( m_dwSinkCaps & eSinkCapKeyboard )
{
CComPtr< ILayerKeyboard > pLayer;
m_pSink->QueryInterface( &pLayer );
pLayer->KeyboardEvent( nMsg, wParam, lParam );
}
}
bool cLayerSite::sendPopupCancel( MouseState *pMS )
{
if( m_dwSinkCaps & eSinkCapPopup )
{
CComPtr< ILayerPopup > pLayer;
m_pSink->QueryInterface( &pLayer );
VARIANT_BOOL bContinue;
pLayer->PopupCancel( pMS, &bContinue );
return !!bContinue;
}
// Default action is to cancel the popup
return false;
}
STDMETHODIMP cLayerSite::Destroy()
{
cManager::_p->m_destroy.push_back( this );
AddRef();
return S_OK;
}
STDMETHODIMP cLayerSite::CreateChild(LayerParams *params, ILayer *pSink)
{
CComObject< cLayerSite > *pChild;
CComObject< cLayerSite >::CreateInstance( &pChild );
pChild->create( params, this, pSink );
m_children.push_back( pChild );
return S_OK;
}
STDMETHODIMP cLayerSite::GetSink(REFIID iid, void **ppvItf)
{
return m_pSink->QueryInterface( iid, ppvItf );
}
STDMETHODIMP cLayerSite::Invalidate()
{
for( cLayerSite *pSite = this; pSite != NULL; pSite = pSite->m_pParent )
{
if( !( pSite->m_params.render & eRenderTransparent ) || !( pSite->m_params.render & eRenderClipped ) || pSite->m_pParent == NULL )
break;
}
pSite->m_params.render |= eRenderNext;
return S_OK;
}
STDMETHODIMP cLayerSite::get_PluginSite(IPluginSite **ppSite)
{
*ppSite = cManager::_p;
( *ppSite )->AddRef();
return S_OK;
}
STDMETHODIMP cLayerSite::Reformat()
{
if( m_params.pos.right != m_params.pos.left && m_params.pos.top != m_params.pos.bottom &&
m_dwSinkCaps & eSinkCapRender )
m_params.render |= eRenderReformatNext;
return S_OK;
}
STDMETHODIMP cLayerSite::GetParentSink(REFIID iid, void **ppvItf)
{
for( cLayerSite *pSite = m_pParent; pSite != NULL; pSite = pSite->m_pParent )
{
HRESULT hRes = pSite->m_pSink->QueryInterface( iid, ppvItf );
if( SUCCEEDED( hRes ) )
// Found our requested interface, return happy
return hRes;
}
return E_NOINTERFACE;
}
STDMETHODIMP cLayerSite::get_Position(LPRECT pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_params.pos;
return S_OK;
}
STDMETHODIMP cLayerSite::put_Position(LPRECT newVal)
{
_ASSERTE( newVal != NULL );
_ASSERTE( newVal->right >= newVal->left && newVal->bottom >= newVal->top );
m_params.pos = *newVal;
if( !( m_params.render & eRenderClipped ) )
{
// This is unclipped, check the buffer size
bool bHasBuffer = ( m_params.pos.right > m_params.pos.left && m_params.pos.bottom > m_params.pos.top );
if( bHasBuffer )
{
SIZE sz = { m_params.pos.right - m_params.pos.left, m_params.pos.bottom - m_params.pos.top };
if( m_pBuffer.p == NULL )
cManager::_p->CreateCanvas( &sz, &m_pBuffer );
else
m_pBuffer->put_Size( &sz );
}
else
{
if( m_pBuffer.p != NULL )
m_pBuffer.Release();
}
}
// Mark for format change only if area > 0
Reformat();
return S_OK;
}
STDMETHODIMP cLayerSite::get_ID(long *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_params.ID;
return S_OK;
}
STDMETHODIMP cLayerSite::get_ChildCount(long *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_children.size();
return S_OK;
}
STDMETHODIMP cLayerSite::get_Child(long nIndex, ePositionType posType, ILayerSite **pVal)
{
_ASSERTE( pVal != NULL );
if( posType == ePositionByIndex )
{
if( nIndex < 0 || nIndex >= m_children.size() )
// Out of range
return E_INVALIDARG;
*pVal = m_children[ nIndex ];
( *pVal )->AddRef();
return S_OK;
}
if( posType != ePositionByID )
// Invalid position type
return E_INVALIDARG;
// Scan for child by ID
for( cChildList::iterator i = m_children.begin(); i != m_children.end(); ++ i )
{
if( ( *i )->m_params.ID == nIndex )
{
*pVal = *i;
( *pVal )->AddRef();
return S_OK;
}
}
// Invalid Index
return E_INVALIDARG;
}
void cLayerSite::moveChildToFront(long nIndex) {
// TODO : Fix this, it doesn't properly move the Z order of the children if they are at the front
if( m_children.back()->m_params.ID == nIndex )
return;
for (cChildList::iterator i = m_children.begin(); i != m_children.end(); ++i) {
if((*i)->m_params.ID == nIndex) {
cLayerSite *layerSite = *i;
m_children.erase(i);
m_children.push_back(layerSite);
break;
}
}
}
STDMETHODIMP cLayerSite::moveToFront() {
_ASSERTE(m_pParent);
m_pParent->moveChildToFront(m_params.ID);
return S_OK;
}
STDMETHODIMP cLayerSite::CaptureKeyboard()
{
// Cancel capture in the existing keyboard capture- if any
// Don't fire EndCapture if we already have the capture. cyn -- 15/10/2002
if( ( cManager::_p->m_pKeyboard != NULL ) && ( cManager::_p->m_pKeyboard != this ) )
cManager::_p->m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE );
// Start capturing
cManager::_p->m_pKeyboard = this;
return S_OK;
}
STDMETHODIMP cLayerSite::IsChild(ILayerSite *pSite, VARIANT_BOOL bTestUnclipped, VARIANT_BOOL *pbIsChild)
{
cLayerSite *pInternalSite = static_cast< cLayerSite * >( pSite );
*pbIsChild = ( ( bTestUnclipped ) ? isChild( pInternalSite ) : isClippedChild( pInternalSite ) ) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP cLayerSite::put_Popup(VARIANT_BOOL newVal)
{
if( newVal )
{
#ifdef _DEBUG
// Check for an existing popup record
for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i )
_ASSERTE( *i != this );
#endif
// Ok, add it into the list
cManager::_p->m_popups.push_back( this );
}
else
{
for( cManager::cLayerList::iterator i = cManager::_p->m_popups.begin(); i != cManager::_p->m_popups.end(); ++ i )
{
if( *i == this )
{
cManager::_p->m_popups.erase( i );
return S_OK;
}
}
// This popup is not in the list
_ASSERTE( FALSE );
}
return S_OK;
}
STDMETHODIMP cLayerSite::get_ScreenPosition(LPRECT pVal)
{
CComPtr< ICanvas > pPrimary;
cManager::_p->GetPrimarySurface( &pPrimary );
{
ClipParams cp;
pPrimary->GetClipParams( &cp );
// First push the identity RECT
RECT rcIdentity = { 0, 0, cp.window.right - cp.window.left, cp.window.bottom - cp.window.top };
VARIANT_BOOL bVisible;
pPrimary->PushClipRect( &rcIdentity, &bVisible );
// Now set the origin
POINT pt = { cp.window.left, cp.window.top };
pPrimary->OffsetOrg( &pt, &bVisible );
}
// ::MessageBox( NULL, _T( "cLayerSite::get_ScreenPosition" ), _T( "Inject.dll" ), MB_OK );
clipCanvas( pPrimary );
// Extract the bounds
ClipParams cp;
pPrimary->GetClipParams( &cp );
*pVal = cp.window;
return S_OK;
}
STDMETHODIMP cLayerSite::StartTimer(long nID, long nInterval)
{
#ifdef _DEBUG
// Walk through the list of timers to make sure the ID isn't in use
for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); ++ i )
_ASSERTE( i->m_nID != nID );
#endif
// NOTE: An interval of 0 is valid in that it'll fire every frame, this would be an
// alternate method to creating an animated layer
_ASSERTE( nInterval >= 0 );
// The layer should implement ILayerTimer
_ASSERTE( m_dwSinkCaps & eSinkCapTimer );
// Add in the timer
cTimer t = { ::timeGetTime(), nID, nInterval, 0 };
m_timers.push_back( t );
return S_OK;
}
STDMETHODIMP cLayerSite::EndTimer(long nID)
{
// Find the timer by ID
for( cTimerList::iterator i = m_timers.begin(); i != m_timers.end(); ++ i )
{
if( i->m_nID == nID )
{
m_timers.erase( i );
return S_OK;
}
}
return E_INVALIDARG;
}
STDMETHODIMP cLayerSite::get_Transparent(VARIANT_BOOL *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = ( m_params.render & eRenderTransparent ) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP cLayerSite::put_Transparent(VARIANT_BOOL newVal)
{
if( newVal )
m_params.render |= eRenderTransparent;
else
m_params.render &= ~eRenderTransparent;
return S_OK;
}
STDMETHODIMP cLayerSite::put_Alpha(long Alpha)
{
m_Alpha = Alpha;
return S_OK;
}