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>
410 lines
10 KiB
C++
410 lines
10 KiB
C++
// View.cpp : Implementation of cView
|
|
#include "stdafx.h"
|
|
#include "Inject.h"
|
|
#include "View.h"
|
|
|
|
#include "RootLayer.h"
|
|
#include "Manager.h"
|
|
|
|
#include "InjectApi.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cView
|
|
|
|
cView::~cView()
|
|
{
|
|
m_pRoot->m_pBars->RemoveBar( m_nViewID );
|
|
m_pRoot->m_pPanel->RemoveView( m_nViewID );
|
|
|
|
m_pRoot->removeView( this );
|
|
}
|
|
|
|
void cView::loadSchema( BSTR strSchema, IUnknown **ppRootControl )
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
_ASSERTE( strSchema != NULL );
|
|
|
|
// Create a new XML document and load this up
|
|
MSXML::IXMLDOMDocumentPtr pDoc;
|
|
pDoc.CreateInstance( __uuidof( MSXML::DOMDocument ), NULL, CLSCTX_INPROC_SERVER );
|
|
|
|
VARIANT_BOOL bSuccess;
|
|
if( strSchema[ 0 ] == OLESTR( '<' ) )
|
|
bSuccess = pDoc->loadXML( strSchema );
|
|
else
|
|
{
|
|
// Load from a file source
|
|
pDoc->async = VARIANT_FALSE;
|
|
|
|
TCHAR szPath[ MAX_PATH ];
|
|
bSuccess = pDoc->load( ::InjectMapPath( eInjectPathAgent, OLE2T( strSchema ), szPath ) );
|
|
}
|
|
|
|
if( !bSuccess )
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
// The document failed to load, get the error info for posterity
|
|
MSXML::IXMLDOMParseErrorPtr pErr = pDoc->parseError;
|
|
|
|
long nCode = pErr->errorCode;
|
|
long nFilePos = pErr->filepos;
|
|
long nLine = pErr->line;
|
|
long nLinePos = pErr->linepos;
|
|
_bstr_t strReason = pErr->reason;
|
|
_bstr_t strText = pErr->srcText;
|
|
|
|
TCHAR szError[ 1024 ];
|
|
::_stprintf( szError, _T( "0x%08X (%i, %i): %s" ),
|
|
nCode, nLine, nLinePos, OLE2T( strReason ) );
|
|
|
|
::MessageBox( cManager::_p->m_hMain, szError, _T( "XML Parse Error" ), MB_ICONERROR | MB_OK );
|
|
|
|
// Give the user a chance to break and look at this lovely info
|
|
_ASSERTE( FALSE );
|
|
|
|
return;
|
|
}
|
|
|
|
// Get the root element and check it out
|
|
loadSchemaObject( pDoc->documentElement, ppRootControl );
|
|
}
|
|
|
|
void cView::loadSchemaObject( IUnknown *pObject, IUnknown **ppRootControl )
|
|
{
|
|
MSXML::IXMLDOMElementPtr pRoot = pObject;
|
|
|
|
_ASSERTE( pRoot->tagName == _bstr_t( _T( "view" ) ) );
|
|
|
|
// Get the view parameters
|
|
_variant_t vIconModule = pRoot->getAttribute( _T( "iconlibrary" ) ),
|
|
vIcon = pRoot->getAttribute( _T( "icon" ) ),
|
|
vTitle = pRoot->getAttribute( _T( "title" ) ),
|
|
vLeft = pRoot->getAttribute( _T( "left" ) ),
|
|
vTop = pRoot->getAttribute( _T( "top" ) ),
|
|
vWidth = pRoot->getAttribute( _T( "width" ) ),
|
|
vHeight = pRoot->getAttribute( _T( "height" ) );
|
|
|
|
// We *must* have a title
|
|
_ASSERTE( vTitle.vt == VT_BSTR );
|
|
|
|
// Fill this into a view param
|
|
_ASSERTE( vIcon.vt != VT_NULL );
|
|
m_nIcon = ( vIcon.vt != VT_NULL ) ? static_cast< long >( vIcon ) + 0x06000000 : 0;
|
|
|
|
if( vIconModule.vt == VT_BSTR )
|
|
cManager::_p->LoadResourceModule( vIconModule.bstrVal, &m_nIconModule );
|
|
else
|
|
m_nIconModule = 0;
|
|
|
|
if(vLeft.vt == VT_NULL)
|
|
m_nLeft = 0;
|
|
else
|
|
m_nLeft = static_cast< long >(vLeft);
|
|
|
|
if(vTop.vt == VT_NULL)
|
|
m_nTop = 70;
|
|
else
|
|
m_nTop = static_cast< long >(vTop);
|
|
|
|
if(vWidth.vt == VT_NULL)
|
|
m_nWidth = 180;
|
|
else
|
|
m_nWidth = static_cast< long >(vWidth);
|
|
|
|
if(vHeight.vt == VT_NULL)
|
|
{
|
|
SIZE szScreen;
|
|
cManager::_p->GetScreenSize( &szScreen );
|
|
m_nHeight = szScreen.cy/2;
|
|
}
|
|
else
|
|
m_nHeight = static_cast< long >(vHeight);
|
|
|
|
m_strTitle = vTitle.bstrVal;
|
|
|
|
// The properly made schema should have a single control child
|
|
MSXML::IXMLDOMElementPtr pControl = pRoot->selectSingleNode( _T( "control" ) );
|
|
|
|
_ASSERTE( pControl.GetInterfacePtr() != NULL );
|
|
|
|
pControl->QueryInterface( ppRootControl );
|
|
}
|
|
|
|
STDMETHODIMP cView::get_Control(BSTR strName, IControl **pVal)
|
|
{
|
|
_ASSERTE( strName != NULL );
|
|
_ASSERTE( pVal != NULL );
|
|
|
|
// Search for a matching control name
|
|
for( cNamedControlList::iterator i = m_controls.begin(); i != m_controls.end(); ++ i )
|
|
{
|
|
if( i->m_strName == _bstr_t( strName ) )
|
|
{
|
|
*pVal = i->m_pControl;
|
|
( *pVal )->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// The name was not found
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
STDMETHODIMP cView::putref_Control(BSTR strName, IControl *newVal)
|
|
{
|
|
_ASSERTE( strName != NULL );
|
|
|
|
// First look for a matching name
|
|
for( cNamedControlList::iterator i = m_controls.begin(); i != m_controls.end(); ++ i )
|
|
{
|
|
if( i->m_strName == _bstr_t( strName ) )
|
|
{
|
|
if( newVal == NULL )
|
|
m_controls.erase( i );
|
|
else
|
|
i->m_pControl = newVal;
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if( newVal == NULL )
|
|
// No value to set
|
|
return S_OK;
|
|
|
|
// Add in a new record
|
|
cNamedControl nc;
|
|
nc.m_strName = strName;
|
|
nc.m_pControl = newVal;
|
|
|
|
m_controls.push_back( nc );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::LoadControl(ILayerSite *pParent, long nID, IUnknown *pSource, long *pAssignedID)
|
|
{
|
|
// Usual parameter validation
|
|
_ASSERTE( pParent != NULL );
|
|
_ASSERTE( pSource != NULL );
|
|
_ASSERTE( pAssignedID != NULL );
|
|
|
|
MSXML::IXMLDOMElementPtr pElement = pSource;
|
|
|
|
// Make sure we're starting from the correct tag name
|
|
_ASSERTE( pElement->tagName == _bstr_t( _T( "control" ) ) );
|
|
|
|
// Get the progid and make an instance
|
|
_variant_t strProgID = pElement->getAttribute( _T( "progid" ) );
|
|
_ASSERTE( strProgID.vt == VT_BSTR );
|
|
|
|
CLSID clsid;
|
|
HRESULT hRes = ::CLSIDFromProgID( strProgID.bstrVal, &clsid );
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
|
|
CComPtr< ILayer > pChildLayer;
|
|
hRes = ::CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_ILayer,
|
|
reinterpret_cast< void ** >( &pChildLayer ) );
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
|
|
// Get some position metrics - note, these are optional and will be
|
|
// loaded with 0s - this is for cases when the control is formatted
|
|
// entirely by the parent
|
|
_variant_t vLeft = pElement->getAttribute( _T( "left" ) ),
|
|
vTop = pElement->getAttribute( _T( "top" ) ),
|
|
vWidth = pElement->getAttribute( _T( "width" ) ),
|
|
vHeight = pElement->getAttribute( _T( "height" ) ),
|
|
vUnclipped = pElement->getAttribute( _T( "unclipped" ) ),
|
|
vID = pElement->getAttribute( _T( "ID" ) );
|
|
|
|
long nRealID = ( vID.vt == VT_NULL ) ? nID : static_cast< long >( vID );
|
|
*pAssignedID = nRealID;
|
|
|
|
POINT pt = { ( vLeft.vt != VT_NULL ) ? static_cast< long >( vLeft ) : 0,
|
|
( vTop.vt != VT_NULL ) ? static_cast< long >( vTop ) : 0 };
|
|
|
|
LayerParams lp = { nRealID, { pt.x, pt.y, pt.x + ( ( vWidth.vt != VT_NULL ) ? static_cast< long >( vWidth ) : 0 ),
|
|
pt.y + ( ( vHeight.vt != VT_NULL ) ? static_cast< long >( vHeight ) : 0 ) },
|
|
( vUnclipped.vt != VT_NULL ) ? 0 : eRenderClipped };
|
|
|
|
pParent->CreateChild( &lp, pChildLayer );
|
|
|
|
// Check if this child is named
|
|
_variant_t vName = pElement->getAttribute( _T( "name" ) );
|
|
|
|
if( vName.vt == VT_BSTR )
|
|
{
|
|
// Add the named control
|
|
CComPtr< IControl > pControl;
|
|
pChildLayer->QueryInterface( &pControl );
|
|
putref_Control( vName.bstrVal, pControl );
|
|
}
|
|
|
|
// Ok, the child is made - trick it into loading it's own parameters
|
|
CComPtr< ILayerSchema > pSchema;
|
|
|
|
if( SUCCEEDED( pChildLayer->QueryInterface( &pSchema ) ) )
|
|
pSchema->SchemaLoad( this, pSource );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::LoadSchema(BSTR strXMLSchema)
|
|
{
|
|
long nPreviousView;
|
|
m_pRoot->m_pPanel->get_ActiveView( &nPreviousView );
|
|
m_pRoot->m_pPanel->RemoveView( m_nViewID );
|
|
|
|
CComPtr< IUnknown > pRootControl;
|
|
loadSchema( strXMLSchema, &pRootControl );
|
|
|
|
// Set the bar params
|
|
ViewParams vp = { m_nIcon, m_nIconModule, m_strTitle, m_nLeft, m_nTop, m_nWidth, m_nHeight };
|
|
m_pRoot->m_pBars->put_Bar( m_nViewID, &vp );
|
|
|
|
// Last, create all the controls
|
|
m_pRoot->m_pPanel->LoadView( m_nViewID, this, pRootControl );
|
|
|
|
if( nPreviousView == m_nViewID )
|
|
// Reactivate the view
|
|
m_pRoot->SelectBar( m_nViewID );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::get_Title(BSTR *pVal)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
*pVal = OLE2BSTR( m_strTitle );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::put_Title(BSTR newVal)
|
|
{
|
|
_ASSERTE( newVal != NULL );
|
|
|
|
m_strTitle = newVal;
|
|
|
|
long nActiveView;
|
|
m_pRoot->m_pPanel->get_ActiveView( &nActiveView );
|
|
|
|
ViewParams vp = { m_nIcon, m_nIconModule, m_strTitle, m_nLeft, m_nTop, m_nWidth, m_nHeight };
|
|
m_pRoot->m_pBars->put_Bar( m_nViewID, &vp );
|
|
|
|
// if( nActiveView == m_nViewID )
|
|
// Reload the view
|
|
// m_pRoot->SelectBar( m_nViewID );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::Alert()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::SetIcon(long icon, VARIANT iconlibrary)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
m_nIcon = icon;
|
|
|
|
switch( iconlibrary.vt )
|
|
{
|
|
case VT_ERROR:
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
m_nIconModule = 0;
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
m_nIconModule = reinterpret_cast< long >( ::GetModuleHandle( OLE2T( iconlibrary.bstrVal ) ) );
|
|
break;
|
|
|
|
default:
|
|
// Try and convert everything else to a number
|
|
try
|
|
{
|
|
_variant_t v = iconlibrary;
|
|
m_nIconModule = v;
|
|
}
|
|
catch( ... )
|
|
{
|
|
m_nIconModule = 0;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
long nActiveView;
|
|
m_pRoot->m_pPanel->get_ActiveView( &nActiveView );
|
|
|
|
ViewParams vp = { m_nIcon, m_nIconModule, m_strTitle, m_nLeft, m_nTop, m_nWidth, m_nHeight};
|
|
m_pRoot->m_pBars->put_Bar( m_nViewID, &vp );
|
|
|
|
if( nActiveView == m_nViewID )
|
|
// Reload the view
|
|
m_pRoot->SelectBar( m_nViewID );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::Activate()
|
|
{
|
|
long nActiveView;
|
|
m_pRoot->m_pPanel->get_ActiveView( &nActiveView );
|
|
if (nActiveView != m_nViewID)
|
|
{
|
|
m_pRoot->SelectBar( m_nViewID );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::Deactivate()
|
|
{
|
|
m_pRoot->m_pPanel->Deactivate();
|
|
if(cManager::_p->m_pKeyboard!=NULL)
|
|
{
|
|
cManager::_p->m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE );
|
|
cManager::_p->m_pKeyboard=NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::put_Position(LPRECT pVal)
|
|
{
|
|
|
|
long nActiveView;
|
|
m_pRoot->m_pPanel->get_ActiveView( &nActiveView );
|
|
|
|
if( nActiveView == m_nViewID )
|
|
{
|
|
m_nLeft = pVal->left;
|
|
m_nTop = pVal->top;
|
|
m_nWidth = pVal->right;
|
|
m_nHeight = pVal->bottom;
|
|
|
|
ViewParams vp = {m_nIcon, m_nIconModule, m_strTitle, m_nLeft, m_nTop, m_nWidth, m_nHeight};
|
|
m_pRoot->m_pPanel->ActivateView(m_nViewID, &vp );
|
|
Fire_Activate();
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cView::get_Position(LPRECT pVal)
|
|
{
|
|
pVal->left = m_nLeft;
|
|
pVal->top = m_nTop;
|
|
pVal->right = m_nWidth;
|
|
pVal->bottom = m_nHeight;
|
|
return S_OK;
|
|
}
|