openDecal/Native/Inject/Manager.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

1632 lines
41 KiB
C++

// Manager.cpp : Implementation of cManager
#include "stdafx.h"
#include <stdio.h>
#include "Inject.h"
#include "Manager.h"
#include "InjectApi.h"
#include "LayerSite.h"
#include "RootLayer.h"
#include "Canvas.h"
#include "IconCache.h"
#include "Image.h"
#include "FontCache.h"
#include "SolidImage.h"
#include "InputBuffer.h"
#include <stdio.h>
const IID EVTID_AcHooks = { 0xEB282FE5, 0x7170, 0x4a37, { 0xA2, 0x6E, 0x92, 0xAF, 0x36, 0x38, 0x5D, 0x2C } };
const IID LIBID_Decal = { 0xFF7F5F6D, 0x34E0, 0x4B6F, { 0xB3, 0xBB, 0x81, 0x41, 0xDE, 0x2E, 0xF7, 0x32 } };
const IID IID_Plugins = { 0x702D3901, 0xC13A, 0x448e, { 0x88, 0x71, 0xEC, 0xDC, 0x8B, 0xC8, 0xD0, 0x79 } };
/////////////////////////////////////////////////////////////////////////////
// cManager
extern HANDLE _hUpdateEnabled;
CComObject< cManager > *cManager::_p = NULL;
static TCHAR szPathBuffer[ MAX_PATH ];
cManager::cManager()
: m_nNextPlugin( 1000 ),
m_pRootSite( NULL ),
m_pMouseOver( NULL ),
m_pMouseDown( NULL ),
m_pKeyboard( NULL ),
m_portal( ::InjectMapPath( eInjectPathDatFile, _T( "portal.dat" ), szPathBuffer ), 1024 ),
m_hMain( NULL ),
m_pfnOld( NULL ),
m_pD( NULL ),
m_p3D( NULL ),
m_p3DDevice( NULL ),
m_pPrimarySurface( NULL ),
m_lpSurface( NULL ),
m_bInitialized( false ),
m_lPrevSelKey( NULL ),
m_bContainer( false ),
m_bXMLViewViewer( false ),
m_hDecalDLL( NULL ),
m_eAlphaBlendMode( eAlphaBlendSoftware ),
m_bSoftware( false )
{
// Start the decal object
::CoInitialize( NULL );
HRESULT hRes = ::CoCreateInstance( __uuidof( Decal ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IDecal ),
reinterpret_cast< void ** >( &m_pDecal ) );
// Load the Decal.dll lib to keep CoFreeAllLibraries from destroying it
m_hDecalDLL = ::LoadLibrary ( _T( "Decal.dll" ) );
if( SUCCEEDED( hRes ) )
hRes = m_pDecal->StartServices( );
}
cManager::~cManager()
{
if( m_pDecal.p )
{
m_pDecal->StopServices( );
m_pDecal.Release( );
}
_ASSERTE ( ::GetWindowLong ( m_hMain, GWL_WNDPROC ) == reinterpret_cast< LONG > ( wndProc ) );
::SetWindowLong( m_hMain, GWL_WNDPROC, reinterpret_cast< LONG >( m_pfnOld ) );
m_pfnOld = NULL;
FreeLibrary( m_hDecalDLL );
if( m_bContainer )
::CoUninitialize( );
_p = NULL;
}
void cManager::setDirectDraw( IDirectDraw4 *pDD, IDirect3D3 *pD3D, IDirectDrawSurface4 *pDDS)
{
if( pDD != NULL )
m_pD = pDD;
m_p3D = pD3D;
m_p3DDevice = NULL;
m_pPrimarySurface = pDDS;
setWindow( NULL );
}
void cManager::setSurface( IDirect3DDevice3 *pDevice )
{
m_p3DDevice = pDevice;
m_pDecal->InitGraphics ( m_pD, pDevice );
// Cascade the reformat
if( m_pRootSite != NULL )
m_pRootSite->reformat();
}
struct cManagerSinkCapTest
{
eManagerSinkCaps m_mask;
const IID *m_iid;
};
void (*pfnOldChatMessage)(char*, DWORD) = NULL;
void (*pfnOldChatText)(void) = NULL;
void cManager::convertVersion( LPTSTR szVersion, DWORD &dwVersionMajor, DWORD &dwVersionMinor )
{
int wVersionParts[ 4 ],
*i_ver = wVersionParts;
for( TCHAR *szVersionPart = ::_tcstok( szVersion, _T( "." ) ); szVersionPart != NULL; szVersionPart = ::_tcstok( NULL, _T( "." ) ), ++ i_ver )
::_stscanf( szVersionPart, _T( "%i" ), i_ver );
dwVersionMajor = MAKELONG( wVersionParts[ 1 ], wVersionParts[ 0 ] );
dwVersionMinor = MAKELONG( wVersionParts[ 3 ], wVersionParts[ 2 ] );
}
void cManager::init()
{
USES_CONVERSION;
// Obtain ACHooks Ref & start ACHooks events if we're not in Checksum's Container
if(!m_bContainer)
{
m_pDecal->get_Hooks( &m_pHooks );
IACHooksEventsImpl<ChatMessageHook, cManager>::advise( m_pHooks );
IACHooksEventsImpl<ChatTextHook, cManager>::advise( m_pHooks );
}
// Prepare the root layer and bar manager before loading plugins
// We have to manually create the root site
CComObject< cLayerSite > *pRootSite;
CComObject< cLayerSite >::CreateInstance( &pRootSite );
m_pRootSite = pRootSite;
// Create the paired root layer
CComObject< cRootLayer > *pRootLayer;
CComObject< cRootLayer >::CreateInstance( &pRootLayer );
m_pRootLayer = pRootLayer;
// To circular reference keeps it all intact
LayerParams lp = { 0, { 0, 0, 0, 0 }, eRenderClipped };
m_pRootSite->create( &lp, NULL, pRootLayer );
m_bInitialized = true;
// Set the blending Mode from the Registry
{
RegKey key;
key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" ) );
if(key.QueryDWORDValue(_T("AlphaBlendMode"), reinterpret_cast<unsigned long &>(m_eAlphaBlendMode))!=ERROR_SUCCESS)
m_eAlphaBlendMode = eAlphaBlendSoftware;
}
// Install the input filter
cInputBuffer::init();
long Val=NULL;
// Ok, enumerate all of the plugins and load them
::ReleaseMutex( _hUpdateEnabled );
}
void cManager::term()
{
// Remove the object from the ROT
::WaitForSingleObject( _hUpdateEnabled, INFINITE );
CComPtr< IRunningObjectTable > pROT;
if( SUCCEEDED( ::GetRunningObjectTable( 0, &pROT ) ) )
pROT->Revoke( m_dwROT );
if( m_pRootSite != NULL )
{
m_pRootSite->Destroy( );
clearDestroyList( );
m_pRootSite = NULL;
}
// Terminate the input buffer
cInputBuffer::term( );
m_bInitialized = false;
// Release the ACHooks interface and event connection points
if( !m_bContainer )
{
IACHooksEventsImpl<ChatMessageHook, cManager>::unadvise( m_pHooks );
IACHooksEventsImpl<ChatTextHook, cManager>::unadvise( m_pHooks );
m_pHooks.Release();
}
// Now Destroy the window structure (NOTE: This reference is weak -
// so the destroy method should free memory)
/* if( m_pRootSite != NULL )
{
m_pRootSite->Destroy();
clearDestroyList();
m_pRootSite = NULL;
}
*/
// Make sure the captures are cleared
_ASSERTE( m_pMouseOver == NULL );
_ASSERTE( m_pMouseDown == NULL );
_ASSERTE( m_pKeyboard == NULL );
::ReleaseMutex( _hUpdateEnabled );
}
void cManager::clearDestroyList()
{
{
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++ i )
{
if( i->m_dwSinkCaps & eManagerSinkCapWindowMessage )
{
// I can't figure out how to stop this from AVing. Spent way too much time on it already.
try
{
CComPtr< IWindowsMessageSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->WindowMessageEnd();
}
catch( ... )
{
}
}
}
}
{
for( cLayerList::iterator i = m_destroy.begin(); i != m_destroy.end(); i = m_destroy.erase( i ) )
{
// Do internal destruction
( *i )->destroy();
( *i )->Release();
}
}
}
void cManager::loadPlugin( IUnknown *pUnkPlugin )
{
cPlugin p;
p.m_pPlugin = pUnkPlugin;
p.m_dwSinkCaps = 0;
// Test for sink caps
static cManagerSinkCapTest _capstest[] = {
{ eManagerSinkCapWindowMessage, &IID_IWindowsMessageSink },
{ eManagerSinkCapPlugin, &IID_IPluginSink},
{ eManagerSinkCapRender, &IID_IRenderSink },
{ eManagerSinkCapRender3D, &IID_IRender3DSink },
};
static cManagerSinkCapTest *_end_caps = _capstest + ( sizeof( _capstest ) / sizeof( cManagerSinkCapTest ) );
for( cManagerSinkCapTest *i = _capstest; i != _end_caps; ++ i )
{
CComPtr< IUnknown > pUnk;
if( SUCCEEDED( pUnkPlugin->QueryInterface( *( i->m_iid ), reinterpret_cast< void ** >( &pUnk ) ) ) )
p.m_dwSinkCaps |= i->m_mask;
}
// Don't bother adding plugins without any sink interfaces
if ( p.m_dwSinkCaps != 0 )
m_plugins.push_back( p );
}
void cManager::unloadPlugins ()
{
m_plugins.clear ();
}
void cManager::setWindow( HWND hWnd )
{
// ::MessageBox( NULL, _T( "cManager::setWindow" ), _T( "Inject.dll" ), MB_OK );
// Subclass the window
if( hWnd == m_hMain || hWnd == NULL )
// Do not subclass the window twice
return;
if( m_hMain != NULL )
{
// Unhook the window proc
_ASSERTE ( ::GetWindowLong ( m_hMain, GWL_WNDPROC ) == reinterpret_cast< LONG > ( wndProc ) );
::SetWindowLong( m_hMain, GWL_WNDPROC, reinterpret_cast< LONG >( m_pfnOld ) );
m_pfnOld = NULL;
}
m_hMain = hWnd;
if( m_hMain != NULL )
// Hook the window proc
m_pfnOld = reinterpret_cast< WNDPROC >( ::SetWindowLong( hWnd, GWL_WNDPROC, reinterpret_cast< LONG >( wndProc ) ) );
m_pDecal->put_HWND ( reinterpret_cast< long > ( hWnd ) );
}
void cManager::draw2D( )
{
m_pDecal->Render2D( );
if( m_pRootSite != NULL )
{
_ASSERTMEM( _CrtCheckMemory( ) );
m_pRootSite->format( );
m_pRootSite->prerender( );
_ASSERTMEM( _CrtCheckMemory( ) );
CComPtr< ICanvas > pCanvas;
if (SUCCEEDED (GetPrimarySurface( &pCanvas )))
{
m_pRootSite->render( pCanvas );
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++ i )
{
// Reset the pCanvas alpha
pCanvas->put_Alpha( 255 );
if( i->m_dwSinkCaps & eManagerSinkCapRender )
{
CComPtr< IRenderSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->CustomDraw( pCanvas );
}
}
}
_ASSERTMEM( _CrtCheckMemory( ) );
}
}
void cManager::draw3D()
{
if( m_pRootSite != NULL )
{
}
}
void cManager::sendPreBeginScene()
{
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapRender3D )
{
CComPtr< IRender3DSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->PreBeginScene( m_p3DDevice );
}
}
}
void cManager::sendPostBeginScene()
{
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapRender3D )
{
CComPtr< IRender3DSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->PostBeginScene( m_p3DDevice );
}
}
}
void cManager::sendPreEndScene()
{
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapRender3D )
{
CComPtr< IRender3DSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->PreEndScene( m_p3DDevice );
}
}
}
void cManager::sendPostEndScene()
{
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapRender3D )
{
CComPtr< IRender3DSink > pSink;
i->m_pPlugin->QueryInterface( &pSink );
pSink->PostEndScene( m_p3DDevice );
}
}
}
void cManager::removeImage( cImage *pImage )
{
for( cImagesList::iterator i = m_images.begin(); i != m_images.end(); ++ i )
{
if( *i == pImage )
{
m_images.erase( i );
return;
}
}
// Not found - boo!
_ASSERTE( FALSE );
}
void cManager::removeFont( cFontCache *pFont )
{
for( cFontsList::iterator i = m_fonts.begin(); i != m_fonts.end(); ++ i )
{
if( *i == pFont )
{
m_fonts.erase( i );
return;
}
}
// Not found - boo!
_ASSERTE( FALSE );
}
void cManager::enableSoftwareMode( )
{
m_bSoftware = true;
}
LRESULT cManager::localWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
/* if((uMsg==WM_NCACTIVATE))/* || (uMsg==WM_ACTIVATE) || (uMsg==WM_ACTIVATEAPP) || (uMsg==WM_KILLFOCUS))
return 0;*/
// When destory comes through, shut down the decal object
if ( uMsg == WM_DESTROY )
{
m_pDecal->StopServices ();
m_pDecal.Release ();
return ::CallWindowProc( m_pfnOld, m_hMain, uMsg, wParam, lParam );
}
if( ( m_pRootSite == NULL ) || ( ( m_p3DDevice == NULL ) && ( !m_bContainer ) && ( !m_bSoftware ) ) )
// Quick return when we aren't initialized
return ::CallWindowProc( m_pfnOld, m_hMain, uMsg, wParam, lParam );
// Forwards messages to the sinks accepting the windows messages
for( cPluginList::iterator i = m_plugins.begin(); i != m_plugins.end(); ++ i )
{
if( i->m_dwSinkCaps & eManagerSinkCapWindowMessage )
{
CComPtr< IWindowsMessageSink > pSink;
if( i->m_pPlugin->QueryInterface( &pSink ) == S_OK )
{
VARIANT_BOOL bEat = VARIANT_FALSE;
pSink->WindowMessage( reinterpret_cast< long >( hWnd ), uMsg, wParam, lParam, &bEat );
if( bEat )
// This message was eaten stop processing
return 0;
}
}
}
// Return if there is no 3D Device
if( m_p3DDevice == NULL && !m_bContainer )
return ::CallWindowProc( m_pfnOld, m_hMain, uMsg, wParam, lParam );
if( uMsg >= WM_MOUSEFIRST && uMsg < WM_MOUSELAST )
{
// Process enter/exit messages
POINTS ptm = MAKEPOINTS( lParam );
if( !m_bContainer )
{
D3DCLIPSTATUS cs;
m_p3DDevice->GetClipStatus( &cs );
ptm.y -= ( 28 - static_cast< short >( cs.miny ) );
}
POINT ptLocal;
CComPtr< ICanvas > pPrimary;
cLayerSite *pHit = NULL;
if (SUCCEEDED (GetPrimarySurface( &pPrimary )))
{
pHit = m_pRootSite->hitTest( ptm, &ptLocal, pPrimary );
if( m_pMouseDown != NULL || pHit != NULL )
{
if( m_pMouseDown != NULL )
m_pMouseDown->sendMouseEvent( uMsg, wParam, lParam );
else
pHit->sendMouseEvent( uMsg, wParam, lParam );
}
}
// Ok - fill out the structure with our fancy info
MouseState ms = { ( pHit == NULL ) ? NULL : pHit->m_pSink, { ptm.x, ptm.y }, { ( pHit == NULL ) ? 0 : ptLocal.x, ( pHit == NULL ) ? 0 : ptLocal.y },
( ::GetAsyncKeyState( VK_CONTROL ) & 0x80000000 ) ? VARIANT_TRUE : VARIANT_FALSE,
( ::GetAsyncKeyState( VK_SHIFT ) & 0x80000000 ) ? VARIANT_TRUE : VARIANT_FALSE };
bool bEat = false;
// First we check for button up messages which end capture
if( uMsg == WM_LBUTTONUP )
{
if( m_pMouseDown != NULL )
{
// Send the mouse up message and end capture
m_pMouseDown->sendMouseUp( &ms );
// Reset the mouse in, so enter/exit messages get sent properly
// First, check if enter/exit messages are
if( m_pMouseDown->isClippedChild( pHit ) )
m_pMouseOver = m_pMouseDown;
else
{
// We have not hit a child of the mouse down, reset the mouse over
// to our parent (which has not received the mouse out message)
if( m_pMouseDown->m_params.render & eRenderClipped )
m_pMouseOver = m_pMouseDown->m_pParent;
else
// If the item is unclipped, then we must send all enter messages
m_pMouseOver = NULL;
}
bEat = true;
m_pMouseDown = NULL;
}
}
// Next, send enter/exit messages
if( pHit != m_pMouseOver )
{
if( m_pMouseDown != NULL )
{
// There is a capture, send enter/exit messages only to the one with capture
bool bPreviousHit = m_pMouseDown->isClippedChild( m_pMouseOver );
if( bPreviousHit != m_pMouseDown->isClippedChild( pHit ) )
{
if( bPreviousHit )
m_pMouseDown->sendMouseExit( m_pMouseDown->m_pParent, &ms );
else
m_pMouseDown->sendMouseEnter( m_pMouseDown->m_pParent, &ms );
}
}
else
{
// Find the common parent
cLayerSite *pCommonParent;
if( pHit == NULL || m_pMouseOver == NULL )
pCommonParent = NULL;
else
pCommonParent = m_pMouseOver->getCommonClippedParent( pHit );
if( m_pMouseOver != NULL )
m_pMouseOver->sendMouseExit( pCommonParent, &ms );
if( pHit != NULL )
pHit->sendMouseEnter( pCommonParent, &ms );
}
m_pMouseOver = pHit;
}
// Next, send movement messages
if( m_pMouseDown != NULL )
m_pMouseDown->sendMouseMove( &ms );
else if( m_pMouseOver != NULL )
m_pMouseOver->sendMouseMove( &ms );
// Last, send mouse capture messages
if( uMsg == WM_LBUTTONDOWN )
{
if( m_pMouseOver != NULL )
{
m_pMouseDown = m_pMouseOver;
m_pMouseDown->sendMouseDown( &ms );
bEat = true;
}
// Check for popups that require closing
for( cLayerList::iterator i = m_popups.begin(); i != m_popups.end(); )
{
if( !( *i )->isChild( m_pMouseOver ) && !( *i )->sendPopupCancel( &ms ) )
{
i = m_popups.erase( i );
continue;
}
++ i;
}
// Check if we should be cancelling a keyboard capture
if( m_pKeyboard != NULL )
{
if( !m_pKeyboard->isClippedChild( m_pMouseDown ) )
{
// The user is clicking on something other than the keyboard capture,
// so end capture
m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE );
m_pKeyboard = NULL;
}
}
}
if( uMsg == WM_LBUTTONDBLCLK )
{
if( m_pMouseOver != NULL )
{
m_pMouseOver->sendMouseDblClk( &ms );
bEat = true;
}
}
if( bEat )
{
clearDestroyList();
return 0;
}
}
if( uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST )
{
// We ahve a keyboard message that might be filtered
if(( m_pKeyboard != NULL ) && (uMsg != WM_KEYUP))
{
m_pKeyboard->sendKeyboardEvent( uMsg, wParam, lParam );
// Check if the message is clearing
if( uMsg == WM_CHAR )
{
if( wParam == VK_RETURN )
{
// End with success
// cyn, 15/10/2002
// Clear m_pKeyboard before triggering KeyboardEndCapture,
// This allows KeyboardEndCapture to re-capture the keyboard
// Edit will only allow recapture if VARIANT_FALSE is passed
// I believe Edit is the only control in DecalControls.* that captures the keyboard
cLayerSite *Keyboard = m_pKeyboard;
m_pKeyboard = NULL;
Keyboard->sendKeyboardEndCapture( VARIANT_FALSE );
Keyboard = NULL; // I don't know if it does some smart pointer reference counting or whatever.. can't hurt
clearDestroyList();
return 0;
}
else if( wParam == VK_ESCAPE || wParam == VK_TAB )
{
// End with cancel
m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE );
m_pKeyboard = NULL;
clearDestroyList();
return 0;
}
// Send the key message
KeyState ks = { wParam,
( ::GetAsyncKeyState( VK_CONTROL ) & 0x80000000 ) ? VARIANT_TRUE : VARIANT_FALSE,
( ::GetAsyncKeyState( VK_SHIFT ) & 0x80000000 ) ? VARIANT_TRUE : VARIANT_FALSE };
m_pKeyboard->sendKeyboardChar( &ks );
}
// Eat all other keyboard messages when there's a capture
clearDestroyList();
return 0;
}
// Carry on, nothing special here
}
if( uMsg == WM_ACTIVATEAPP && !wParam )
{
// The application is being deactivated - clear all mouse and keyboard captures
MouseState ms = { NULL, { 0, 0 }, { 0, 0 }, VARIANT_FALSE, VARIANT_FALSE };
if( m_pMouseDown )
{
cLayerSite *pMouseDownParent = ( m_pMouseDown->m_params.render & eRenderClipped ) ?
m_pMouseDown->m_pParent : NULL;
// Do a mouse exit from the captured control
if( m_pMouseDown->isClippedChild( m_pMouseOver ) )
{
// First exit the mouse down layer
m_pMouseDown->sendMouseExit( pMouseDownParent, &ms );
m_pMouseOver = pMouseDownParent;
}
else
m_pMouseOver = pMouseDownParent;
// Send the mouse up message
m_pMouseDown->sendMouseUp( &ms );
m_pMouseDown = NULL;
}
// Do an exit for any remaining mouse overs
if( m_pMouseOver != NULL )
{
m_pMouseOver->sendMouseExit( NULL, &ms );
m_pMouseOver = NULL;
}
// Attempt to close all popups
for( cLayerList::iterator i = m_popups.begin(); i != m_popups.end(); )
{
if( !( *i )->sendPopupCancel( &ms ) )
i = m_popups.erase( i );
else
++ i;
}
if( m_pKeyboard )
{
m_pKeyboard->sendKeyboardEndCapture( VARIANT_TRUE );
m_pKeyboard = NULL;
}
}
clearDestroyList( );
return ::CallWindowProc( m_pfnOld, m_hMain, uMsg, wParam, lParam );
}
LRESULT cManager::wndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
_ASSERTE ( cManager::_p != NULL );
return cManager::_p->localWndProc( hWnd, uMsg, wParam, lParam );
}
void cManager::createSurface( LPSIZE psz, IDirectDrawSurface4 **ppSurf )
{
DDSURFACEDESC2 ddsd;
::memset( &ddsd, 0, sizeof( DDSURFACEDESC2 ) );
ddsd.dwSize = sizeof( DDSURFACEDESC2 );
ddsd.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
// Set the pixel format to the same as the primary surface
CComPtr< ICanvas > pCanvas;
if (SUCCEEDED (GetPrimarySurface( &pCanvas )))
{
CComPtr< IDirectDrawSurface4 > pPrimary;
pCanvas->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pPrimary ) );
pPrimary->GetPixelFormat( &ddsd.ddpfPixelFormat );
// Now make a drawing surface of the same size as our client area
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.dwWidth = psz->cx;
ddsd.dwHeight = psz->cy;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
HRESULT hRes = m_pD->CreateSurface( &ddsd, ppSurf, NULL );
_ASSERTE( SUCCEEDED( hRes ) );
DDCOLORKEY ddc = { 0x07FF, 0x07FF };
( *ppSurf )->SetColorKey( DDCKEY_SRCBLT, &ddc );
}
_ASSERTMEM( _CrtCheckMemory( ) );
}
STDMETHODIMP cManager::UnloadPlugin(long nID)
{
return E_NOTIMPL;
}
STDMETHODIMP cManager::GetDirectDraw(REFIID iid, void **ppvItf)
{
_ASSERTE( ppvItf != NULL );
return m_pD->QueryInterface( iid, ppvItf );
}
STDMETHODIMP cManager::GetPrimarySurface(ICanvas **ppCanvas)
{
_ASSERTE( ppCanvas != NULL );
// _ASSERTE( m_p3DDevice != NULL );
if ( m_bContainer )
{
// Create a canvas object
CComObject< cCanvas > *pPrimCanvas;
CComObject< cCanvas >::CreateInstance( &pPrimCanvas );
GetScreenSize( &pPrimCanvas->m_sz );
pPrimCanvas->m_pSurface = m_pPrimarySurface;
RECT rc;
GetWindowRect(m_hMain, &rc);
ClipParams cClip = { { static_cast< long >( 0 ), static_cast< long >( 0 ), static_cast< long >( rc.right - rc.left ), static_cast< long >( rc.bottom - rc.top ) }, { 0, 0 }, VARIANT_TRUE };
pPrimCanvas->m_clipping.push( cClip );
pPrimCanvas->AddRef( );
*ppCanvas = pPrimCanvas;
}
else
{
CComPtr< IDirectDrawSurface4 > pPrimary;
HRESULT hRes = m_p3DDevice->GetRenderTarget( &pPrimary );
if( FAILED( hRes ) )
return E_FAIL;
// Create a canvas object
CComObject< cCanvas > *pPrimCanvas;
CComObject< cCanvas >::CreateInstance( &pPrimCanvas );
GetScreenSize( &pPrimCanvas->m_sz );
pPrimCanvas->m_pSurface = pPrimary;
D3DCLIPSTATUS cs;
m_p3DDevice->GetClipStatus( &cs );
// Set up the clipping parameters (depends on the 3d clipping area)
ClipParams cClip = { { static_cast< long >( cs.minx ), static_cast< long >( cs.miny ), static_cast< long >( cs.maxx ), static_cast< long >( cs.maxy ) },
{ 0, 0 }, VARIANT_TRUE };
pPrimCanvas->m_clipping.push( cClip );
pPrimCanvas->AddRef();
*ppCanvas = pPrimCanvas;
}
return S_OK;
}
STDMETHODIMP cManager::Get3DDevice(REFIID iid, void **ppvItf)
{
_ASSERTE( ppvItf != NULL );
return m_p3DDevice->QueryInterface( iid, ppvItf );
}
STDMETHODIMP cManager::LoadBitmapFile(BSTR strFilename, IImageCache **ppImage)
{
_ASSERTE( strFilename != NULL );
_ASSERTE( ppImage != NULL );
USES_CONVERSION;
LPCTSTR szFilename = OLE2T( strFilename );
TCHAR szPath[ MAX_PATH ];
::InjectMapPath( eInjectPathAgent, szFilename, szPath );
// First search the image cache for a matching file
for( cImagesList::iterator i = m_images.begin(); i != m_images.end(); ++ i )
{
if( ( *i )->m_source == cImage::eFile && ::_tcsicmp( ( *i )->m_szFilename, szPath ) == 0 )
{
// Here's the match - return the existing image with another reference
( *i )->AddRef();
*ppImage = *i;
return S_OK;
}
}
// The image wasn't found, so make a new entry
CComObject< cImage > *pNewImage;
CComObject< cImage >::CreateInstance( &pNewImage );
pNewImage->m_source = cImage::eFile;
::_tcscpy( pNewImage->m_szFilename, szPath );
m_images.push_back( pNewImage );
pNewImage->AddRef();
*ppImage = pNewImage;
return S_OK;
}
STDMETHODIMP cManager::GetIconCache(LPSIZE psz, IIconCache **ppCache)
{
_ASSERTE( psz != NULL );
_ASSERTE( psz->cx > 0 && psz->cy > 0 );
_ASSERTE( ppCache != NULL );
for( cIconsList::iterator i = m_icons.begin(); i != m_icons.end(); ++ i )
{
if( ( *i )->m_szIcon.cx == psz->cx && ( *i )->m_szIcon.cy == psz->cy )
{
*ppCache = ( *i );
( *i )->AddRef();
return S_OK;
}
}
// Not found, so create a new cache
CComObject< cIconCache > *pNewCache;
CComObject< cIconCache >::CreateInstance( &pNewCache );
pNewCache->m_szIcon = *psz;
pNewCache->m_nEdge = 8;
pNewCache->AddRef();
m_icons.push_back( pNewCache );
*ppCache = pNewCache;
// Make the icon cache actually cache
pNewCache->AddRef();
return S_OK;
}
STDMETHODIMP cManager::LoadBitmapPortal(long nFile, IImageCache **ppImage)
{
_ASSERTE( ppImage != NULL );
DWORD dwFile = *reinterpret_cast< DWORD* >( &nFile );
for( cImagesList::iterator i = m_images.begin(); i != m_images.end(); ++ i )
{
if( ( *i )->m_source == cImage::ePortal && ( *i )->m_dwID == dwFile )
return ( *i )->QueryInterface( IID_IImageCache, reinterpret_cast< void ** >( ppImage ) );
}
// The image wasn't found, so make a new entry
CComObject< cImage > *pNewImage;
CComObject< cImage >::CreateInstance( &pNewImage );
pNewImage->m_source = cImage::ePortal;
pNewImage->m_dwID = dwFile;
pNewImage->AddRef();
m_images.push_back( pNewImage );
*ppImage = pNewImage;
return S_OK;
}
STDMETHODIMP cManager::CreateFont(BSTR strFaceName, long nHeight, long nFlags, IFontCache **ppFont)
{
_ASSERTE( strFaceName != NULL );
_ASSERTE( ppFont != NULL );
_ASSERTE( nHeight > 0 );
USES_CONVERSION;
LPCTSTR szFaceName = OLE2T( strFaceName );
// Iterate through existing foonts to see if there's a match
for( cFontsList::iterator i = m_fonts.begin(); i != m_fonts.end(); ++ i )
{
if( ( *i )->m_lf.lfHeight == nHeight &&
::_tcscmp( szFaceName, ( *i )->m_lf.lfFaceName ) == 0 &&
( ( *i )->m_lf.lfWeight == FW_BOLD ) == !!( nFlags & eFontBold ) &&
!!( ( *i )->m_lf.lfItalic ) == !!( nFlags & eFontItalic ) &&
!!( ( *i )->m_lf.lfUnderline ) == !!( nFlags &eFontUnderline ) )
// Here's the match
return ( *i )->QueryInterface( IID_IFontCache, reinterpret_cast< void ** >( ppFont ) );
}
// Not Found, create a new font
CComObject< cFontCache > *pNewFont;
CComObject< cFontCache >::CreateInstance( &pNewFont );
::memset( &pNewFont->m_lf, '\0', sizeof( LOGFONT ) );
pNewFont->m_lf.lfHeight = nHeight;
::_tcscpy( pNewFont->m_lf.lfFaceName, szFaceName );
if( nFlags & eFontBold )
pNewFont->m_lf.lfWeight = FW_BOLD;
if( nFlags & eFontItalic )
pNewFont->m_lf.lfItalic = TRUE;
if( nFlags & eFontUnderline )
pNewFont->m_lf.lfUnderline = TRUE;
// Commit the font
m_fonts.push_back( pNewFont );
pNewFont->AddRef();
*ppFont = pNewFont;
return S_OK;
}
STDMETHODIMP cManager::GetScreenSize(LPSIZE sz)
{
_ASSERTE( sz != NULL );
RECT rc;
::GetClientRect( m_hMain, &rc );
sz->cx = rc.right - rc.left;
sz->cy = rc.bottom - rc.top;
return S_OK;
}
STDMETHODIMP cManager::CreateCanvas(LPSIZE psz, ICanvas **ppCanvas)
{
_ASSERTE( psz != NULL );
_ASSERTE( psz->cx > 0 && psz->cy > 0 );
_ASSERTE( ppCanvas != NULL );
CComObject< cCanvas > *pCanvas;
CComObject< cCanvas >::CreateInstance( &pCanvas );
pCanvas->m_sz = *psz;
// Set the root clipper
ClipParams cClip = { { 0, 0, psz->cx, psz->cy },
{ 0, 0 }, VARIANT_TRUE };
pCanvas->m_clipping.push( cClip );
*ppCanvas = pCanvas;
pCanvas->AddRef();
return S_OK;
}
STDMETHODIMP cManager::CreateView(ViewParams *pParams, ILayer *pLayer, IView **ppView)
{
CComPtr< IRootLayer > pRoot;
m_pRootSite->m_pSink->QueryInterface( &pRoot );
return pRoot->CreateView( pParams, pLayer, ppView );
}
STDMETHODIMP cManager::LoadView(BSTR strSchema, IView **ppView)
{
CComPtr< IRootLayer > pRoot;
m_pRootSite->m_pSink->QueryInterface( &pRoot );
return pRoot->LoadView( strSchema, ppView );
}
STDMETHODIMP cManager::CreateBrushImage(long nColor, IImageCache **ppImg)
{
CComObject< cBrushImage > *pBrush;
CComObject< cBrushImage >::CreateInstance( &pBrush );
pBrush->put_Color( nColor );
*ppImg = pBrush;
pBrush->AddRef();
return S_OK;
}
STDMETHODIMP cManager::LoadImageSchema(IUnknown *pSchema, IImageCache **ppImg)
{
MSXML::IXMLDOMElementPtr pElement = pSchema;
// Look for elements that specify a background image
_variant_t vFileSrc = pElement->getAttribute( _T( "imagefilesrc" ) ),
vPortalSrc = pElement->getAttribute( _T( "imageportalsrc" ) ),
vBrushSrc = pElement->getAttribute( _T( "imagebrushsrc" ) );
if( vFileSrc.vt != VT_NULL )
{
_ASSERTE( vFileSrc.vt = VT_BSTR );
// We has a file source, attempt to create an image
HRESULT hRes = LoadBitmapFile( vFileSrc.bstrVal, ppImg );
_ASSERTE( SUCCEEDED( hRes ) );
}
else if( vPortalSrc.vt != VT_NULL )
{
try
{
long nFileID = static_cast< long >( vPortalSrc );
_ASSERTE( nFileID > 0 );
_ASSERTE( nFileID < 0xFFFFL );
long nPortalID = 0x06000000 + nFileID;
// It certainly converted properly - attempt to load the bitmap
HRESULT hRes = LoadBitmapPortal( nPortalID, ppImg );
_ASSERTE( SUCCEEDED( hRes ) );
}
catch( ... )
{
// It must be possible to convert the portal src into
// a long int value.
_ASSERTE( FALSE );
}
}
else if( vBrushSrc.vt != VT_NULL )
{
try
{
long nColor = vBrushSrc;
CreateBrushImage( nColor, ppImg );
}
catch( ... )
{
// Failed to convert to long
_ASSERTE( FALSE );
}
}
else
// Otherwise, this background is transparent
*ppImg = NULL;
return S_OK;
}
STDMETHODIMP cManager::CreateFontSchema(long nDefHeight, long nDefOptions, IUnknown *pSchema, IFontCache **ppCache)
{
MSXML::IXMLDOMElementPtr pElement = pSchema;
_variant_t vFacename = pElement->getAttribute( _T( "fontface" ) ),
vSize = pElement->getAttribute( _T( "fontsize" ) ),
vStyle = pElement->getAttribute( _T( "fontstyle" ) );
_bstr_t strFacename;
long nHeight = nDefHeight,
nStyle = nDefOptions;
if( vFacename.vt != VT_NULL )
{
_ASSERTE( vFacename.vt == VT_BSTR );
strFacename = vFacename.bstrVal;
}
else
{
BSTR bstrFontName;
get_FontName(&bstrFontName);
strFacename = bstrFontName;//_T( "Times New Roman" );
}
if( vSize.vt != VT_NULL )
nHeight = static_cast< long >( vSize );
if( vStyle.vt != VT_NULL )
{
_ASSERTE( vStyle.vt == VT_BSTR );
nStyle = 0;
// Make a copy of the value since strtok will destroy it nicely
_bstr_t strStyle = vStyle.bstrVal;
for( wchar_t *pTok = ::wcstok( strStyle, L" " ); pTok != NULL; pTok = ::wcstok( NULL, L" " ) )
{
if( ::_wcsicmp( L"bold", pTok ) == 0 )
nStyle |= eFontBold;
else if( ::_wcsicmp( L"italic", pTok ) == 0 )
nStyle |= eFontItalic;
else if( ::_wcsicmp( L"underline", pTok ) == 0 )
nStyle |= eFontUnderline;
else
// Unknown token value, data problem
_ASSERTE( FALSE );
}
}
return CreateFont( strFacename, nHeight, nStyle, ppCache );
}
STDMETHODIMP cManager::LoadResourceModule(BSTR strLibrary, long *pnModule)
{
USES_CONVERSION;
LPCTSTR szLibrary = OLE2T( strLibrary );
HMODULE hLoaded = GetModuleHandle( szLibrary );
if( hLoaded == NULL )
{
TCHAR szPath[ MAX_PATH ];
*pnModule = reinterpret_cast< long >( ::LoadLibrary( ::InjectMapPath( eInjectPathAgent, szLibrary, szPath ) ) );
_ASSERTE( *pnModule != NULL );
}
else
*pnModule = reinterpret_cast< long >( hLoaded );
return S_OK;
}
STDMETHODIMP cManager::get_ResourcePath(BSTR *pVal)
{
_ASSERTE( pVal != NULL );
TCHAR szPath[ MAX_PATH ];
*pVal = T2BSTR( ::InjectMapPath( eInjectPathAgent, _T( "" ), szPath ) );
return S_OK;
}
STDMETHODIMP cManager::get_Plugin(BSTR strProgID, LPDISPATCH *pVal)
{
_ASSERTE( strProgID != NULL );
_ASSERTE( pVal != NULL );
// Prepend a fully-qualified service id
_bstr_t strPath ( _T( "plugins\\" ) );
strPath += strProgID;
return m_pDecal->get_Object ( strPath, IID_IDispatch, reinterpret_cast< LPVOID * > ( pVal ) );
}
STDMETHODIMP cManager::get_NetworkFilter(BSTR strProgID, LPDISPATCH *pVal)
{
_ASSERTE( strProgID != NULL );
_ASSERTE( pVal != NULL );
// Prepend a fully-qualified service id
_bstr_t strPath ( _T( "services\\DecalNet.NetService\\" ) );
strPath += strProgID;
return m_pDecal->get_Object ( strPath, IID_IDispatch, reinterpret_cast< LPVOID * > ( pVal ) );
}
STDMETHODIMP cManager::LoadViewObject(IUnknown *pSchema, IView **ppView)
{
CComPtr< IRootLayer > pRoot;
m_pRootSite->m_pSink->QueryInterface( &pRoot );
return pRoot->LoadViewObject( pSchema, ppView );
}
STDMETHODIMP cManager::CreateInputBuffer(IInputBuffer **ppInput)
{
CComObject< cInputBuffer > *pNew;
CComObject< cInputBuffer >::CreateInstance( &pNew );
return pNew->QueryInterface( ppInput );
}
STDMETHODIMP cManager::get_HWND(long *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = reinterpret_cast< long >( m_hMain );
return S_OK;
}
STDMETHODIMP cManager::get_Focus(VARIANT_BOOL *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = ( m_pKeyboard != NULL ) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP cManager::get_OldWndProc(long *pOldWndProc)
{
_ASSERTE( pOldWndProc != NULL );
*pOldWndProc = reinterpret_cast< long > (m_pfnOld);
return S_OK;
}
STDMETHODIMP cManager::put_CurrentSelection( long nID)
{
return m_pHooks->put_CurrentSelection( nID );
}
STDMETHODIMP cManager::get_CurrentSelection(long *nID)
{
return m_pHooks->get_CurrentSelection( nID );
}
STDMETHODIMP cManager::put_PreviousSelection(long nID)
{
return m_pHooks->put_PreviousSelection( nID );
}
STDMETHODIMP cManager::get_PreviousSelection(long *nID)
{
return m_pHooks->get_PreviousSelection( nID );
}
STDMETHODIMP cManager::WriteToChatWindow(BSTR szText, long lColor)
{
return m_pHooks->ChatOut( szText, lColor );
}
STDMETHODIMP cManager::RawWriteToChatWindow(BSTR szText, long lColor)
{
return m_pHooks->RawChatOut( szText, lColor );
}
STDMETHODIMP cManager::SetCursorPosition(long x, long y)
{
return m_pHooks->SetCursorPosition( x, y );
}
STDMETHODIMP cManager::QueryMemLoc(BSTR bstrTag, long *pVal)
{
if( m_bContainer )
{
*pVal = NULL;
return S_OK;
}
return m_pHooks->QueryMemLoc( bstrTag, pVal );
}
STDMETHODIMP cManager::QueryKeyboardMap(BSTR bstrName, long *pAsciiVal)
{
USES_CONVERSION;
// Para > this damned proc
RegKey key;
//HANDLE hFile;
DWORD dwType = REG_EXPAND_SZ;
DWORD dwLengthPath = MAX_PATH;
DWORD dwLengthMap;
//DWORD dwFileSize;
//DWORD lpdwBytesRead;
//int count = 0;
//char* pDest;
//char *pEnd;
TCHAR tempbuf[MAX_PATH];
TCHAR tempfile[MAX_PATH];
*pAsciiVal = 0;
if (key.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00"), KEY_QUERY_VALUE) == ERROR_SUCCESS)
{
ZeroMemory(tempbuf, sizeof(tempbuf));
if (key.QueryStringValue(_T("Path"), tempbuf, &dwLengthPath) == ERROR_SUCCESS)
{
dwLengthMap = MAX_PATH;
ZeroMemory(tempfile, sizeof(tempfile));
if (key.QueryValue(_T("CurrentInputMap"), &dwType, tempfile, &dwLengthMap) != ERROR_SUCCESS)
lstrcat(tempbuf, _T("\\default.map"));
else
{
// someone less peaved than me can choose a better answer to the 2 strcat's
lstrcat(tempbuf, _T("\\"));
lstrcat(tempbuf, tempfile);
}
}
else
return E_FAIL;
}
else
return E_FAIL;
//::MessageBox(NULL, tempbuf, "QKM Path", 0);
// The following requires more testing than what i've given it.
FILE * fKeyMap = fopen(tempbuf, "r");
if (fKeyMap == NULL)
return S_FALSE;
DWORD dwNumMaps;
fscanf(fKeyMap, "%i\r\n", &dwNumMaps);
DWORD dwBlah1;
DWORD dwChar;
DWORD dwBlah3;
char szName[256];
DWORD dwBlah5;
DWORD dwBlah6;
// Not sure if this method is faster than the code below,
// but it's a bit easier to tell what's going on
while (fscanf(fKeyMap, "%i\t%i\t%i\t%s\t%i\t%i\r\n", &dwBlah1, &dwChar, &dwBlah3, szName, &dwBlah5, &dwBlah6) != 0)
{
if (stricmp(szName, OLE2A(bstrName)) == 0)
break;
memset(szName, 0, 256);
dwChar = 0;
}
*pAsciiVal = (long)dwChar;
fclose(fKeyMap);
return S_OK;
/*
hFile = CreateFile(tempbuf, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(hFile==INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
dwFileSize = GetFileSize(hFile, NULL);
char* pBuffer;
pBuffer = new char[dwFileSize+1];
BOOL bSuccess = ReadFile (hFile, pBuffer, dwFileSize, &lpdwBytesRead, 0);
::CloseHandle (hFile);
if (!bSuccess)
{
delete[] pBuffer;
return E_FAIL;
}
pBuffer [lpdwBytesRead] = 0;
pDest = strstr(pBuffer, OLE2T(bstrName));
if(pDest != NULL)
{
while(pDest != pBuffer)
{
pDest--;
if(*pDest=='\t')
{
count++;
if(count==3)
{
*pEnd=0;
pDest++;
*pAsciiVal = atoi(pDest);
break;
}
pEnd = pDest;
}
}
}
delete[] pBuffer;
return S_OK;
*/
}
STDMETHODIMP cManager::CastSpell(long lSpellID, long lObjectID)
{
return m_pHooks->CastSpell( lSpellID, lObjectID );
}
STDMETHODIMP cManager::MoveItem(long lObjectID, long lPackID, long lSlot, long lStack)
{
if( lStack == 0 )
return m_pHooks->MoveItem( lObjectID, lPackID, lSlot, VARIANT_FALSE );
else
return m_pHooks->MoveItem( lObjectID, lPackID, lSlot, VARIANT_TRUE );
}
STDMETHODIMP cManager::SelectItem(long lObjectID)
{
return m_pHooks->SelectItem( lObjectID );
}
STDMETHODIMP cManager::UseItem(long lObjectID, long lUseOnSelectedItem)
{
return m_pHooks->UseItem( lObjectID, lUseOnSelectedItem );
}
STDMETHODIMP cManager::get_CombatState(long *pVal)
{
return m_pHooks->get_CombatState( pVal );
}
STDMETHODIMP cManager::get_ChatState(VARIANT_BOOL *pVal)
{
HRESULT HRes = m_pHooks->get_ChatState( pVal );
if( m_pKeyboard != NULL )
*pVal = VARIANT_TRUE;
return HRes;
}
STDMETHODIMP cManager::UseItemEx(long Use, long UseOn)
{
return m_pHooks->UseItemEx( Use, UseOn );
}
STDMETHODIMP cManager::get_Decal(IDecal **pVal) {
return m_pDecal->QueryInterface(pVal);
}
STDMETHODIMP cManager::GetFellowStats(long charID)
{
return m_pHooks->GetFellowStats( charID );
}
STDMETHODIMP cManager::get_Hooks(IACHooks **pVal)
{
return m_pHooks->QueryInterface(pVal);
}
STDMETHODIMP cManager::RedrawBar()
{
m_pRootSite->reformat() ;
return S_OK ;
}
/////////////////////////////////////////////////////////////////////////////
// Used to determine the font to use in Decal
/////////////////////////////////////////////////////////////////////////////
static _bstr_t g_bstrDecalFontName = "Times New Roman";
static bool g_bDecalFontRead = false;
STDMETHODIMP cManager::get_FontName(BSTR *pFontName)
{
// Do we need to read the font name???
if (!g_bDecalFontRead)
{
RegKey key;
// Open the main Decal Key
if (key.Create(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Decal")) == ERROR_SUCCESS)
{
// Get font type
DWORD dwFontType;
if (key.QueryDWORDValue("FontType", dwFontType) == ERROR_SUCCESS)
{
// Act on type
switch (dwFontType)
{
case 0: // Default Font
{
// No-op
}
break;
case 1: // Current AC Client Font
{
RegKey k;
TCHAR szFontName[512];
DWORD dwCount = 512;
// Get the AC Client font
k.Create(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00"));
if (k.QueryStringValue("Font", szFontName, &dwCount) == ERROR_SUCCESS)
{
g_bstrDecalFontName = _bstr_t(szFontName);
}
k.Close();
}
break;
case 2: // Custom Font Name
{
TCHAR szFontName[512];
DWORD dwCount = 512;
// Get the custom font
if (key.QueryStringValue("FontName", szFontName, &dwCount) == ERROR_SUCCESS)
{
g_bstrDecalFontName = _bstr_t(szFontName);
}
}
break;
}
}
}
key.Close();
// Assume its found (don't try again)
g_bDecalFontRead = true;
//MessageBox(NULL, (LPCTSTR) g_bstrDecalFontName, NULL, MB_OK);
}
// Pass back the font name
*pFontName = g_bstrDecalFontName;
return S_OK;
}
void cManager::onChatMessage( BSTR bstrText, long lColor, VARIANT_BOOL *pbEat )
{
VARIANT_BOOL bEat = VARIANT_FALSE;
for( cPluginList::iterator i = _p->m_plugins.begin(); i != _p->m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapPlugin )
{
CComPtr<IPluginSink> pPluginSink;
i->m_pPlugin->QueryInterface( &pPluginSink );
pPluginSink->ChatMessage( bstrText, &lColor, &bEat );
if( bEat == VARIANT_TRUE )
*pbEat = VARIANT_TRUE;
}
}
}
void cManager::onChatText( BSTR bstrText, VARIANT_BOOL *pbEat )
{
VARIANT_BOOL bEat = VARIANT_FALSE;
for( cPluginList::iterator i = _p->m_plugins.begin(); i != _p->m_plugins.end(); ++i )
{
if( i->m_dwSinkCaps & eManagerSinkCapPlugin )
{
CComPtr<IPluginSink> pPluginSink;
i->m_pPlugin->QueryInterface( &pPluginSink );
pPluginSink->ChatText( bstrText, &bEat );
if( bEat == VARIANT_TRUE )
*pbEat = VARIANT_TRUE;
}
}
}