// Manager.cpp : Implementation of cManager #include "stdafx.h" #include #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 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::advise( m_pHooks ); IACHooksEventsImpl::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(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::unadvise( m_pHooks ); IACHooksEventsImpl::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 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 pPluginSink; i->m_pPlugin->QueryInterface( &pPluginSink ); pPluginSink->ChatText( bstrText, &bEat ); if( bEat == VARIANT_TRUE ) *pbEat = VARIANT_TRUE; } } }