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>
992 lines
No EOL
24 KiB
C++
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;
|
|
} |