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>
305 lines
No EOL
8 KiB
C++
305 lines
No EOL
8 KiB
C++
// ScriptPlugin.cpp : Implementation of cScriptPlugin
|
|
#include "stdafx.h"
|
|
#include "PlainText.h"
|
|
#include "ScriptPlugin.h"
|
|
#include "../Inject/Inject.h"
|
|
#include "ScriptView.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cScriptPlugin
|
|
|
|
void cScriptPlugin::getCLSID( BSTR *pbstrCLSID )
|
|
{
|
|
MSXML::IXMLDOMAttributePtr pAttr = m_pPlugin->selectSingleNode( _T( "/plugin/@clsid" ) );
|
|
|
|
_ASSERTE( pAttr.GetInterfacePtr() != NULL );
|
|
|
|
*pbstrCLSID = OLE2BSTR( pAttr->value.bstrVal );
|
|
}
|
|
|
|
void cScriptPlugin::getLanguage( BSTR *pbstrLanguage )
|
|
{
|
|
MSXML::IXMLDOMAttributePtr pAttr = m_pPlugin->selectSingleNode( _T( "/plugin/@language" ) );
|
|
|
|
if( pAttr.GetInterfacePtr() == NULL )
|
|
*pbstrLanguage = T2BSTR( _T( "VBScript" ) );
|
|
else
|
|
*pbstrLanguage = OLE2BSTR( pAttr->value.bstrVal );
|
|
}
|
|
|
|
HRESULT cScriptPlugin::LoadScript(BSTR strFilename)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
HRESULT hRes = ::CoCreateInstance( __uuidof( MSXML::DOMDocument ), NULL, CLSCTX_INPROC_SERVER,
|
|
__uuidof( MSXML::IXMLDOMDocument ), reinterpret_cast< void ** >( &m_pPlugin ) );
|
|
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
bool bLoad = !!m_pPlugin->load( strFilename );
|
|
|
|
if( !bLoad )
|
|
{
|
|
// The document failed to load, get the error info for posterity
|
|
MSXML::IXMLDOMParseErrorPtr pErr = m_pPlugin->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( NULL, 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 E_FAIL;
|
|
}
|
|
|
|
// Looking good
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::CreateInstance(IDecalEnum *pInitData, REFIID iid, LPVOID *pObject)
|
|
{
|
|
CComVariant vFile;
|
|
HRESULT hRes = pInitData->get_Property( _bstr_t( "File" ), &vFile );
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
if( vFile.vt != VT_BSTR )
|
|
return E_FAIL;
|
|
|
|
m_strFilename = vFile.bstrVal;
|
|
return static_cast< IDecalSurrogate * >( this )->QueryInterface( iid, pObject );
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::Initialize( IPluginSite2 *pSite )
|
|
{
|
|
USES_CONVERSION;
|
|
m_pSite = pSite;
|
|
|
|
// First, map the map and load the script file
|
|
CComPtr< IDecal > pDecal;
|
|
m_pSite->get_Decal( &pDecal );
|
|
|
|
CComBSTR strTruePath;
|
|
HRESULT hRes = pDecal->MapPath( m_strFilename, &strTruePath );
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
hRes = LoadScript( strTruePath );
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
// Set up the scripting environment, the default scripting language
|
|
// is VBScript
|
|
CComBSTR strScript;
|
|
|
|
getLanguage( &strScript );
|
|
hRes = createScriptEngine( strScript );
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
|
|
// Load the script text
|
|
CComPtr< IActiveScriptParse > pParse;
|
|
m_pScript->QueryInterface( &pParse );
|
|
|
|
pParse->InitNew();
|
|
|
|
addNamedItem( _bstr_t( _T( "Site" ) ), static_cast< IDispatch * >( this ) );
|
|
|
|
MSXML::IXMLDOMElementPtr pScript = m_pPlugin->selectSingleNode( _T( "/plugin/script" ) );
|
|
|
|
// Load the main script block
|
|
if( pScript.GetInterfacePtr() != NULL )
|
|
{
|
|
EXCEPINFO ei;
|
|
HRESULT hRes = pParse->ParseScriptText( pScript->text, NULL, NULL, NULL, 0, 0,
|
|
SCRIPTITEM_ISVISIBLE, NULL, &ei );
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
} else {
|
|
::MessageBox(NULL, "Couldn't load the main script block", "cScriptPlugin::Initialize", MB_OK);
|
|
}
|
|
|
|
// Walk through the intrinsic object
|
|
MSXML::IXMLDOMNodeListPtr pNetworks = m_pPlugin->selectNodes( _T( "/plugin/decal" ) );
|
|
for( MSXML::IXMLDOMElementPtr pNetwork = pNetworks->nextNode(); pNetwork.GetInterfacePtr() != NULL; pNetwork = pNetworks->nextNode() )
|
|
{
|
|
CComPtr< IDispatch > pObject;
|
|
HRESULT hRes = pDecal->get_Object( pNetwork->getAttribute( _T( "path" ) ).bstrVal, IID_IDispatch, reinterpret_cast< void ** >( &pObject ) );
|
|
if( FAILED( hRes ) )
|
|
{
|
|
::MessageBox(NULL, "SCRIPT ERROR: Couldn't load decal object", OLE2A(pNetwork->getAttribute(_T("path")).bstrVal), MB_OK);
|
|
continue;
|
|
}
|
|
|
|
// Add the item
|
|
addNamedItem( pNetwork->getAttribute( _T( "name" ) ).bstrVal, pObject );
|
|
}
|
|
|
|
// Walk through the instance objects
|
|
MSXML::IXMLDOMNodeListPtr pObjects = m_pPlugin->selectNodes( _T( "/plugin/object" ) );
|
|
for( MSXML::IXMLDOMElementPtr pObject = pObjects->nextNode(); pObject.GetInterfacePtr() != NULL; pObject = pObjects->nextNode() )
|
|
{
|
|
_variant_t vProgid = pObject->getAttribute( _T( "progid" ) );
|
|
|
|
if( vProgid.vt == VT_NULL )
|
|
{
|
|
_ASSERT( FALSE );
|
|
continue;
|
|
}
|
|
|
|
CComPtr< IDispatch > pInstance;
|
|
CLSID clsid;
|
|
HRESULT hRes = ::CLSIDFromProgID( vProgid.bstrVal, &clsid );
|
|
|
|
if( FAILED( hRes ) )
|
|
{
|
|
_ASSERT( FALSE );
|
|
continue;
|
|
}
|
|
|
|
hRes = ::CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, reinterpret_cast< void ** >( &pInstance ) );
|
|
|
|
if( FAILED( hRes ) )
|
|
{
|
|
_ASSERT( FALSE );
|
|
continue;
|
|
}
|
|
|
|
// Add the item
|
|
addNamedItem( pObject->getAttribute( _T( "name" ) ).bstrVal, pInstance );
|
|
}
|
|
|
|
// Start up the plugin
|
|
m_pScript->SetScriptState(SCRIPTSTATE_CONNECTED);
|
|
Fire_Initialize();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::Terminate()
|
|
{
|
|
// Shut down the plugin
|
|
Fire_Terminate();
|
|
|
|
m_pScript->SetScriptState( SCRIPTSTATE_DISCONNECTED );
|
|
m_pScript->Close();
|
|
|
|
m_pSite.Release();
|
|
m_pPlugin.Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::CreateObject( BSTR strProgID, LPDISPATCH *pDisp )
|
|
{
|
|
if( pDisp == NULL )
|
|
{
|
|
_ASSERT( FALSE );
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hRes;
|
|
CLSID clsid;
|
|
if( strProgID[ 0 ] == OLESTR( '{' ) )
|
|
hRes = ::CLSIDFromString( strProgID, &clsid );
|
|
else
|
|
hRes = ::CLSIDFromProgID( strProgID, &clsid );
|
|
|
|
if( FAILED( hRes ) )
|
|
return hRes;
|
|
|
|
return ::CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, reinterpret_cast< void ** >( pDisp ) );
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::WriteToChatWindow(BSTR szText, long lColor)
|
|
{
|
|
getPluginSite()->WriteToChatWindow(szText, lColor);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::MessageBox(BSTR Title, BSTR Text)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
::MessageBox(NULL, OLE2A(Text), OLE2A(Title), MB_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
IPluginSite * cScriptPlugin::getPluginSite()
|
|
{
|
|
CComPtr< IDecal > pDecal;
|
|
m_pSite->get_Decal ( &pDecal );
|
|
|
|
CComPtr< IInjectService > pInject;
|
|
CComPtr< IPluginSite > pSite;
|
|
HRESULT hRes = pDecal->get_Object ( _bstr_t ( _T( "services\\DecalPlugins.InjectService" ) ),
|
|
__uuidof ( IInjectService ), reinterpret_cast< LPVOID * > ( &pInject ) );
|
|
|
|
pInject->get_Site(&pSite);
|
|
return pSite;
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::LoadView(BSTR Text, IView **pView)
|
|
{
|
|
getPluginSite()->LoadView(Text, pView);
|
|
return S_OK;
|
|
}
|
|
|
|
void cScriptPlugin::removeView( CScriptView *pView )
|
|
{
|
|
for( cViewList::iterator i = m_views.begin(); i != m_views.end(); ++ i )
|
|
{
|
|
if( *i == pView )
|
|
{
|
|
m_views.erase( i );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// The view was not found in the list
|
|
_ASSERTE( FALSE );
|
|
}
|
|
|
|
void cScriptPlugin::postRemoveView( CScriptView *pView )
|
|
{
|
|
m_destroy.push_back( pView );
|
|
}
|
|
|
|
STDMETHODIMP cScriptPlugin::CreateView(BSTR strTemplateName, LPDISPATCH *ppNewView)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
TCHAR szQuery[ 255 ];
|
|
::_stprintf( szQuery, _T( "/plugin/view[@name='%s']" ), OLE2T( strTemplateName ) );
|
|
|
|
MSXML::IXMLDOMElementPtr pView = m_pPlugin->selectSingleNode( szQuery );
|
|
|
|
if( pView.GetInterfacePtr() == NULL )
|
|
return E_INVALIDARG;
|
|
|
|
CComObject< CScriptView > *pNewView;
|
|
CComObject< CScriptView >::CreateInstance( &pNewView );
|
|
|
|
CComPtr< IDispatch > pDispPlugin;
|
|
m_pScript->GetScriptDispatch( NULL, &pDispPlugin );
|
|
|
|
CComBSTR strLanguage;
|
|
getLanguage( &strLanguage );
|
|
|
|
pNewView->loadView( this, pView, ppNewView );
|
|
|
|
return S_OK;
|
|
} |