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>
1632 lines
41 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|