openDecal/Native/Decal/ACHooks.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

2618 lines
57 KiB
C++

// ACHooks.cpp : Implementation of CDecalApp and DLL registration.
#include "stdafx.h"
#include "ACHooks.h"
#include <math.h>
#include <time.h> /* Heyus 23 March 2003 */
#include ".\achooks.h"
/*
I believe in VC6, the limit of unnamed variables (_bstr_t("foo")) has been reached,
which caused the following error:
F:\Decal\source\Decal\ACHooks.cpp(467) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
This macro allows us to use a single variable, while keeping more or less the same syntax.
A variable of type _bstr_t named _Unnamed must be declared in any procedure this is used.
Note - This only works with inline strings -> L"Foo"
*/
#define BSTRT(x) (_Unnamed = L##x, _Unnamed)
/////////////////////////////////////////////////////////////////////////////
cACHooks* cACHooks::s_pACHooks = NULL;
long g_lObjectDestroyedProc = 0;
long g_lSelectItemHijackProc = 0;
long g_lIdentifyHijackProc = 0;
long g_lToolTextProc = 0;
long g_lToolText2Proc = 0;
void (__fastcall *pfnOldChatMessage)(int _ecx, int _edx, char *, DWORD ) = NULL;
void (*pfnOldChatText)() = NULL;
void (*pfnUseItem)( DWORD, DWORD ) = NULL;
void (*pfnMoveItemEx)( DWORD, DWORD, DWORD ) = NULL;
void ( __fastcall *pfnInternalStringDestructor)( qString * ) = NULL;
long (*pfnSendMessageToID)( qString *, long ) = NULL;
long (*pfnSendMessageToName)( qString *, qString * ) = NULL;
long (*pfnSendMessageByMask)( long, qString * ) = NULL;
long (*pfnLocalChatText)( qString * ) = NULL;
long (*pfnLocalChatEmote)( qString * ) = NULL;
qString* ( __fastcall *pfnInternalStringConstructor)( qString *, long, char * ) = NULL;
bool g_bTimestamp;
char *g_szTimestampFormat;
DWORD g_lTimestampColor;
char g_charBufferPreviousCall;
extern void __fastcall OnChatMessage( int _ecx, int _edx, char* pText, long dwColor );
extern void CatchToolText();
extern void CatchToolTextAppend();
extern void OnChatText();
extern void IdentifyShortcircuit();
extern void SelectItemHook();
extern void ObjectDestroyedHook();
extern DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement);
cACHooks::cACHooks()
{
g_bTimestamp = false;
s_pACHooks = this;
m_bDecalRef = false;
m_bIdQueueRef = false;
m_bMismatch = true;
m_bPrevSelect = false;
m_bCurrentSelect = false;
m_bMouse = false;
m_bCastSpell = false;
m_bMoveItem = false;
m_bSelectItem = false;
m_bUseItem = false;
m_bAllYourBase = false;
m_bSetCombatState = false;
m_bCombatStateOffset = false;
m_bChatState = false;
m_bRequestID = false;
m_bStackCount = false;
m_bTestFormula = false;
m_bVendorID = false;
m_bBusyState = false;
m_bPointerState = false;
m_bMoveItemEx = false;
m_bFaceHeading = false;
m_bChatMessageAddy = false;
m_bSendMessageToID = false;
m_bSendMessageToName = false;
m_bSendMessageToMask = false;
m_bLocalChatText = false;
m_bLocalChatEmote = false;
m_bSetAutorun = false;
m_bGetVital = false;
m_bGetAttribute = false;
m_bGetSkill = false;
m_bLogout = false;
m_bSecureTrade_Add = false;
m_bSecureTrade_Add_Off1 = false;
m_bSecureTrade_Add_Off2 = false;
m_bGetSkillInfo = false;
m_bGetAttributeInfo = false;
m_bGetVitalInfo = false;
m_bSelectItemHook = false;
m_bUstAddItem_Useable = false;
m_bRequestShortcircuit = false;
m_bToolTextHook = false;
m_bToolText2Hook = false;
m_bIdleLoc = false;
m_Hooks = 0;
memset(m_HooksEx, 0, sizeof(m_HooksEx));
m_HookCount = 0;
USES_CONVERSION;
_bstr_t _Unnamed;
char szPath[ MAX_PATH ];
DWORD dwCount = MAX_PATH;
g_charBufferPreviousCall = '\n';
DWORD dwTimestamp = 0;
char szTimestampFormat[ MAX_PATH ];
DWORD lTimestampFormatLength = MAX_PATH;
RegKey key;
if( key.Open( HKEY_LOCAL_MACHINE, "SOFTWARE\\Decal", KEY_READ ) == ERROR_SUCCESS )
{
if( key.QueryDWORDValue( _T("Timestamp"), dwTimestamp ) != ERROR_SUCCESS )
dwTimestamp = 0;
if( key.QueryStringValue( _T("TimestampFormat"), szTimestampFormat, &lTimestampFormatLength ) != ERROR_SUCCESS ) /* Heyus 21 March 2003 */
memset( szTimestampFormat, 0, sizeof(szTimestampFormat) ), strncpy( szTimestampFormat, "[%H:%M]", sizeof( szTimestampFormat ) );
if( key.QueryDWORDValue( _T("TimestampColor"), g_lTimestampColor ) != ERROR_SUCCESS )
g_lTimestampColor = 12; // Grey
key.Close();
}
int iStrLen = strlen( szTimestampFormat ) + 2;
g_szTimestampFormat = new char[ iStrLen ];
memset( g_szTimestampFormat, 0, iStrLen );
_snprintf( g_szTimestampFormat, iStrLen, "%s ", szTimestampFormat );
// 0xFFFFFFFF = same color as chat text, for those that want time stamps but don't
// want to infringe upon their 300 max chat window items
if( g_lTimestampColor < 0 || g_lTimestampColor > 22 && g_lTimestampColor != 0xFFFFFFFF )
g_lTimestampColor = 12; // Grey
g_bTimestamp = dwTimestamp ? true : false ;
TCHAR szFilename[ MAX_PATH ];
::GetModuleFileName( NULL, szFilename, MAX_PATH );
LPTSTR strProcessName = ::_tcsrchr( szFilename, _T( '\\' ) );
strProcessName[ 7 ] = _T( '\0' );
if( ::_tcsicmp( strProcessName + 1, _T( "client" ) ) != 0 )
return;
key.Open( HKEY_LOCAL_MACHINE, "SOFTWARE\\Decal\\Agent", KEY_READ );
key.QueryStringValue( _T("AgentPath"), szPath, &dwCount );
strncat( szPath, "\\memlocs.xml", MAX_PATH );
MSXML::IXMLDOMDocumentPtr pMemLocDoc;
pMemLocDoc.CreateInstance( __uuidof( MSXML::DOMDocument ) );
pMemLocDoc->async = false;
VARIANT_BOOL bSuccess = pMemLocDoc->load( szPath );
if( ! bSuccess )
{
std::string szXML;
DecryptXML( szPath, szXML );
if( szXML != "" )
bSuccess = pMemLocDoc->loadXML( _bstr_t( szXML.c_str() ) );
}
if( bSuccess )
{
MSXML::IXMLDOMElementPtr pNode = pMemLocDoc->selectSingleNode( BSTRT( "locations" ) );
long lVerMajor = 0, lVerMinor = 0, lVerRelease = 0;
_variant_t vVersion = pNode->getAttribute( BSTRT( "version" ) );
char *szTemp, *szVersion = OLE2A( vVersion.bstrVal );
// I'm tired and sscanf is crashing - this works even if it's lame
lVerMajor = atol( szVersion );
szTemp = strstr( szVersion, "." ) + 1;
lVerMinor = atol( szTemp );
szTemp = strstr( szTemp, "." ) + 1;
lVerRelease = atol( szTemp );
RegKey rk;
if( rk.Open( HKEY_LOCAL_MACHINE, _T( "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00" ) ) == ERROR_SUCCESS )
{
TCHAR szClientPath[ MAX_PATH ];
DWORD dwPathLength = MAX_PATH;
if( rk.QueryStringValue ( _T( "path" ), szClientPath, &dwPathLength ) == ERROR_SUCCESS )
{
::_tcscpy( szClientPath + ( dwPathLength - 1 ), _T( "\\client.exe" ) );
DWORD dwDummy,
dwVerSize = ::GetFileVersionInfoSize( const_cast< LPTSTR > ( szClientPath ), &dwDummy );
if( dwVerSize != 0 )
{
BYTE *pbVersionInfo = reinterpret_cast< BYTE * >( ::_alloca( dwVerSize ) );
::GetFileVersionInfo( const_cast< LPTSTR > ( szClientPath ), 0, dwVerSize, pbVersionInfo );
VS_FIXEDFILEINFO *vffi;
UINT nLength = sizeof( VS_FIXEDFILEINFO );
if( ::VerQueryValue( pbVersionInfo, _T( "\\" ), reinterpret_cast< LPVOID * >( &vffi ), &nLength ) )
{
if( (static_cast< long >( HIWORD( vffi->dwFileVersionMS ) ) == lVerMajor) &&
(static_cast< long >( LOWORD( vffi->dwFileVersionMS ) ) == lVerMinor) &&
(static_cast< long >( HIWORD( vffi->dwFileVersionLS ) ) == lVerRelease) )
{
m_bMismatch = false;
}
}
}
}
}
MSXML::IXMLDOMNodeListPtr pNodes = pMemLocDoc->selectNodes( BSTRT( "/locations/memloc" ) );
for( pNode = pNodes->nextNode(); pNode.GetInterfacePtr() != NULL; pNode = pNodes->nextNode() )
{
_variant_t vName = pNode->getAttribute( _T( "name" ) ), vValue = pNode->getAttribute( _T( "value" ) );
sMemoryLocation loc;
loc.Name = OLE2A( vName.bstrVal );
loc.Location = wcstoul( vValue.bstrVal, 0, 16 );
m_mLocationList[ loc.Name ] = loc;
}
}
long Val;
if( QueryMemLoc( BSTRT( "PrevItem1" ), &Val ) == S_OK )
m_lPrevSelect[0] = Val;
if( QueryMemLoc( BSTRT( "PrevItem2" ), &Val ) == S_OK )
{
m_lPrevSelect[1] = Val;
m_bPrevSelect = true;
m_Hooks |= ePrevSelect ;
}
if( QueryMemLoc( BSTRT( "CurrentItem1" ), &Val ) == S_OK )
m_lCurrentSelect[0] = Val;
if( QueryMemLoc( BSTRT( "CurrentItem2" ), &Val ) == S_OK )
{
m_lCurrentSelect[1] = Val;
m_bCurrentSelect = true;
m_Hooks |= eCurrentSelect ;
}
if( QueryMemLoc( BSTRT( "ChatMessage" ), &Val ) == S_OK )
pfnOldChatMessage = reinterpret_cast< void (__fastcall*)( int, int, char *, DWORD ) >( Val );
if( QueryMemLoc( BSTRT( "ChatMessageAddy" ), &Val ) == S_OK )
{
m_lChatMessageAddy = Val;
m_bChatMessageAddy = true;
}
if( QueryMemLoc( BSTRT( "ChatText" ), &Val ) == S_OK )
pfnOldChatText = reinterpret_cast< void (*)() >( Val );
if( QueryMemLoc( BSTRT( "Mouse1X" ), &Val ) == S_OK )
m_lMouse[0] = Val;
if( QueryMemLoc( BSTRT( "Mouse2X" ), &Val ) == S_OK )
m_lMouse[1] = Val;
if( QueryMemLoc( BSTRT( "Mouse3X" ), &Val ) == S_OK )
m_lMouse[2] = Val;
if( QueryMemLoc( BSTRT( "Mouse4X" ), &Val ) == S_OK )
{
m_bMouse = true;
m_lMouse[3] = Val;
m_Hooks |= eMouse ;
}
if( QueryMemLoc( BSTRT( "CastSpell" ), &Val ) == S_OK )
{
m_bCastSpell = true;
m_Hooks |= eCastSpell ;
m_lCastSpell = Val;
}
if( QueryMemLoc( BSTRT( "MoveItem" ), &Val ) == S_OK )
{
m_bMoveItem = true;
m_Hooks |= eMoveItem ;
m_lMoveItem = Val;
}
if( QueryMemLoc( BSTRT( "SelectItem" ), &Val ) == S_OK )
{
m_bSelectItem = true;
m_Hooks |= eSelectItem ;
m_lSelectItem = Val;
}
if( QueryMemLoc( BSTRT( "UseItem" ), &Val ) == S_OK )
{
m_bUseItem = true;
m_Hooks |= eUseItem ;
SetHookEx( eUseItemRaw );
SetHookEx( eUseFociSpell );
m_lUseItem = Val;
pfnUseItem = reinterpret_cast< void (*)( DWORD, DWORD ) >( Val );
}
if( QueryMemLoc( BSTRT( "AllYourBase" ), &Val ) == S_OK )
{
// The memloc formerly known as CombatState
m_bAllYourBase = true;
m_Hooks |= eCombatState ;
m_lAllYourBase = Val;
}
if( QueryMemLoc( BSTRT( "SetCombatState" ), &Val ) == S_OK )
{
m_bSetCombatState = true;
m_Hooks |= eSetCombatState ;
m_lSetCombatState = Val;
}
if( QueryMemLoc( BSTRT( "CombatStateOffset" ), &Val ) == S_OK )
{
m_bCombatStateOffset = true;
m_Hooks |= eCombatState ;
m_lCombatStateOffset = Val;
}
if( QueryMemLoc( BSTRT( "ChatState" ), &Val ) == S_OK )
{
m_bChatState = true;
m_Hooks |= eChatState ;
m_lChatState = Val;
}
if( QueryMemLoc( BSTRT( "GetFellowStats" ), &Val ) == S_OK )
{
m_bRequestID = true;
m_lRequestID = Val;
m_Hooks |= eGetFellowStats;
SetHookEx( eRequestID );
}
if( QueryMemLoc( BSTRT( "RequestID" ), &Val ) == S_OK )
{
m_bRequestID = true;
m_lRequestID = Val;
m_Hooks |= eGetFellowStats;
SetHookEx( eRequestID );
}
if( QueryMemLoc( BSTRT( "NumStackItemsSelected" ), &Val ) == S_OK )
{
m_bStackCount = true;
m_Hooks |= eStackCount ;
m_lStackCount = Val;
}
if( QueryMemLoc( BSTRT( "TestFormula" ), &Val ) == S_OK )
m_lTestFormula = Val;
if( QueryMemLoc( BSTRT( "TestFormulavtp" ), &Val ) == S_OK )
{
m_bTestFormula = true;
m_Hooks |= eTestFormula ;
m_lTestFormulaVTable = Val;
}
if( QueryMemLoc( BSTRT( "VendorID" ), &Val ) == S_OK )
{
m_bVendorID = true;
m_Hooks |= eVendorID ;
m_lVendorID = Val;
}
if( QueryMemLoc( BSTRT( "ItemBusyState" ), &Val ) == S_OK )
{
m_bBusyState = true;
m_Hooks |= eBusyState ;
m_lBusyState = Val;
}
if( QueryMemLoc( BSTRT( "ItemBusyGUID" ), &Val ) == S_OK )
{
m_bBusyStateID = true;
m_Hooks |= eBusyStateID ;
m_lBusyStateID = Val;
}
if( QueryMemLoc( BSTRT( "PointerState" ), &Val ) == S_OK )
{
m_bPointerState = true;
m_Hooks |= ePointerState ;
m_lPointerState = Val;
}
if( QueryMemLoc( BSTRT( "MoveItemEx" ), &Val ) == S_OK )
{
m_bMoveItemEx = true;
m_Hooks |= eMoveItemEx ;
m_lMoveItemEx = Val;
pfnMoveItemEx = reinterpret_cast< void (*)(DWORD, DWORD, DWORD) >( Val );
}
if( QueryMemLoc( BSTRT( "3DAreaWidth" ), &Val ) == S_OK )
{
m_bArea3DWidth = true;
m_Hooks |= eArea3DWidth ;
m_lpArea3DWidth = reinterpret_cast< long * >( Val );
}
if( QueryMemLoc( BSTRT( "3DAreaHeight" ), &Val ) == S_OK )
{
m_bArea3DHeight = true;
m_Hooks |= eArea3DHeight ;
m_lpArea3DHeight = reinterpret_cast< long * >( Val );
}
if( QueryMemLoc( BSTRT( "ObjectFromGUID" ), &Val ) == S_OK ) {
m_lObjectFromGuid = Val;
SetHookEx( eObjectFromGUID );
if( QueryMemLoc( BSTRT( "ObjectFromGUIDClass" ), &Val ) == S_OK )
{
m_lObjectFromGuidClass = Val;
SetHookEx( eObjectFromGUIDClass );
m_bObjectFromGuid = true;
}
}
m_lMovementThingyParent = m_lMovementThingyOffset = m_lFaceHeading = 0;
if( QueryMemLoc( BSTRT( "MovementThingyParent" ), &Val ) == S_OK)
{
m_lMovementThingyParent = Val;
}
if( QueryMemLoc( BSTRT( "MovementThingyOffset" ), &Val ) == S_OK)
{
m_lMovementThingyOffset = Val;
}
if( QueryMemLoc( BSTRT( "FaceHeading" ), &Val ) == S_OK)
{
m_lFaceHeading = Val;
}
if( QueryMemLoc( BSTRT( "SetAutorun" ), &Val ) == S_OK)
{
m_lSetAutorun = Val;
}
if (m_lMovementThingyParent && m_lMovementThingyOffset && m_lFaceHeading)
{
m_bFaceHeading = true;
m_Hooks |= eFaceHeading;
}
if (m_lMovementThingyParent && m_lMovementThingyOffset && m_lSetAutorun)
{
m_bSetAutorun = true;
m_Hooks |= eSetAutorun;
}
/*
// While the address of ObjectDestroyed is interesting, it isn't actually needed.
// We can't assume that the calls we're hooking call to this address, as they
// might have already been hooked!
if( QueryMemLoc( BSTRT( "ObjectDestroyed"), &Val ) == S_OK )
{
}
*/
long lCall1 = 0, lCall2 = 0;
if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call1"), &Val ) == S_OK )
{
lCall1 = Val;
}
if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call2"), &Val ) == S_OK )
{
lCall2 = Val;
}
if (lCall1 && lCall2)
{
DWORD dwFunc1 = HookCall (lCall1, (DWORD) ObjectDestroyedHook);
DWORD dwFunc2 = HookCall (lCall2, (DWORD) ObjectDestroyedHook);
_ASSERTE (dwFunc1 && (dwFunc1 == dwFunc2));
if (dwFunc1 && (dwFunc1 != dwFunc2))
{
// Doh, okay put them back, something's wrong.
HookCall (lCall1, dwFunc1);
HookCall (lCall2, dwFunc2);
}
else
{
m_Hooks |= eObjectDestroyed;
g_lObjectDestroyedProc = dwFunc1;
}
}
if( QueryMemLoc( BSTRT( "InternalStringConstructor" ), &Val ) == S_OK)
{
m_bInternalStringConstructor = true;
m_lInternalStringConstructor = Val;
pfnInternalStringConstructor = reinterpret_cast< qString *(__fastcall*)(qString *, long, char *) >( Val );
}
if( QueryMemLoc( BSTRT( "InternalStringDestructor" ), &Val ) == S_OK)
{
m_bInternalStringDestructor = true;
m_lInternalStringDestructor = Val;
pfnInternalStringDestructor = reinterpret_cast< void(__fastcall *)(qString *) >( Val );
}
if( QueryMemLoc( BSTRT( "SendMessageToID" ), &Val ) == S_OK)
{
m_bSendMessageToID = true;
m_lSendMessageToID = Val;
pfnSendMessageToID = reinterpret_cast< long(*)(qString *, long) >( Val );
}
if( QueryMemLoc( BSTRT( "SendMessageToName" ), &Val ) == S_OK)
{
m_bSendMessageToName = true;
m_lSendMessageToName = Val;
pfnSendMessageToName = reinterpret_cast< long(*)(qString *, qString *) >( Val );
}
if( QueryMemLoc( BSTRT( "SendMessageToMask" ), &Val ) == S_OK)
{
m_bSendMessageToMask = true;
m_lSendMessageToMask = Val;
pfnSendMessageByMask = reinterpret_cast< long(*)( long, qString * ) >( Val );
}
if( QueryMemLoc( BSTRT( "LocalChatText" ), &Val ) == S_OK)
{
m_bLocalChatText = true;
m_lLocalChatText = Val;
pfnLocalChatText = reinterpret_cast< long(*)(qString *) >( Val );
}
if( QueryMemLoc( BSTRT( "LocalChatEmote" ), &Val ) == S_OK)
{
m_bLocalChatEmote = true;
m_lLocalChatEmote = Val;
pfnLocalChatEmote = reinterpret_cast< long(*)(qString *) >( Val );
}
if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToID )
m_Hooks |= eSendTell;
if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToName )
m_Hooks |= eSendTellEx;
if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatText )
m_Hooks |= eLocalChatText;
if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatEmote )
m_Hooks |= eLocalChatEmote;
if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToMask )
SetHookEx( eSendMessageByMask );
if( QueryMemLoc( BSTRT( "VitalBase" ), &Val ) == S_OK )
{
m_lVitalBase = Val;
}
if( QueryMemLoc( BSTRT( "GetVital" ), &Val ) == S_OK )
{
m_lGetVital = Val;
m_bGetVital = true;
}
if( QueryMemLoc( BSTRT( "GetAttribute" ), &Val ) == S_OK )
{
m_lGetAttribute = Val;
m_bGetAttribute = true;
}
if( QueryMemLoc( BSTRT( "GetSkill" ), &Val ) == S_OK )
{
m_lGetSkill = Val;
m_bGetSkill = true;
}
if( m_lVitalBase )
{
if( m_bGetVital )
m_Hooks |= eGetVital;
if( m_bGetAttribute )
m_Hooks |= eGetAttribute;
if( m_bGetSkill )
m_Hooks |= eGetSkill;
}
if( QueryMemLoc( BSTRT( "Logout" ), &Val ) == S_OK )
{
m_lLogout = Val;
m_bLogout = true;
SetHookEx(eLogout);
}
if (QueryMemLoc(BSTRT( "SecureTrade_Add" ), &Val) == S_OK)
{
m_lSecureTrade_Add = Val;
m_bSecureTrade_Add = true;
}
if (QueryMemLoc(BSTRT( "SecureTrade_Add_Off1" ), &Val) == S_OK)
{
m_lSecureTrade_Add_Off1 = Val;
m_bSecureTrade_Add_Off1 = true;
}
if (QueryMemLoc(BSTRT( "SecureTrade_Add_Off2" ), &Val) == S_OK)
{
m_lSecureTrade_Add_Off2 = Val;
m_bSecureTrade_Add_Off2 = true;
}
if (m_bSecureTrade_Add && m_bSecureTrade_Add_Off1 && m_bSecureTrade_Add_Off2 && m_bAllYourBase)
{
SetHookEx(eSecureTrade_Add);
}
if (QueryMemLoc(BSTRT( "GetSkillInfo" ), &Val) == S_OK)
{
m_lGetSkillInfo = Val;
m_bGetSkillInfo = true;
}
if (QueryMemLoc(BSTRT( "GetVitalInfo" ), &Val) == S_OK)
{
m_lGetVitalInfo = Val;
m_bGetVitalInfo = true;
}
if (QueryMemLoc(BSTRT( "GetAttributeInfo" ), &Val) == S_OK)
{
m_lGetAttributeInfo = Val;
m_bGetAttributeInfo = true;
}
/* I don't believe the vTable is used for any of these, however, if it becomes necessary
the functionality is here to a) detect the problem (crash at 0xFF......), and fix it
without requiring a complete update to Decal */
if (QueryMemLoc(BSTRT( "GetSkillInfo_vT" ), &Val) == S_OK)
{
m_lGetSkillInfo_vT = Val;
}
else
{
m_lGetSkillInfo_vT = 0xFF111111;
}
if (QueryMemLoc(BSTRT( "GetVitalInfo_vT" ), &Val) == S_OK)
{
m_lGetVitalInfo_vT = Val;
}
else
{
m_lGetVitalInfo_vT = 0xFF222222;
}
if (QueryMemLoc(BSTRT( "GetAttributeInfo_vT" ), &Val) == S_OK)
{
m_lGetAttributeInfo_vT = Val;
}
else
{
m_lGetAttributeInfo_vT = 0xFF333333;
}
if (m_lVitalBase) {
if (m_bGetSkillInfo) {
SetHookEx(eSkillInfo);
}
if (m_bGetVitalInfo) {
SetHookEx(eVitalInfo);
}
if (m_bGetAttributeInfo) {
SetHookEx(eAttributeInfo);
}
}
if (QueryMemLoc(BSTRT( "ToolTextHJ" ), &Val) == S_OK)
{
m_lToolTextHJ = Val;
g_lToolTextProc = HookCall( m_lToolTextHJ, (DWORD)CatchToolText );
SetHookEx( eToolText );
m_bToolTextHook = true;
}
if (QueryMemLoc(BSTRT( "ToolText2HJ" ), &Val) == S_OK)
{
m_lToolText2HJ = Val;
g_lToolText2Proc = HookCall( m_lToolText2HJ, (DWORD)CatchToolTextAppend );
SetHookEx( eToolText2 );
m_bToolText2Hook = true;
}
DWORD dwOldProtect;
if( QueryMemLoc( BSTRT( "OnChatText" ), &Val ) == S_OK )
{
VirtualProtect( reinterpret_cast< void * >( Val ), 4, PAGE_EXECUTE_READWRITE, &dwOldProtect );
*reinterpret_cast< long * >( Val ) = ( reinterpret_cast< long >( OnChatText ) - ( Val + 0x4 ) );
}
if( QueryMemLoc( BSTRT( "OnChatMessage" ), &Val ) == S_OK )
{
VirtualProtect( reinterpret_cast< void * >( Val ), 4, PAGE_EXECUTE_READWRITE, &dwOldProtect );
*reinterpret_cast< long * >( Val ) = ( reinterpret_cast< long >( OnChatMessage ) - ( Val + 0x4 ) );
}
m_Hooks |= eHooksAvailEx;
if( QueryMemLoc( BSTRT( "SelectItemHook" ), &Val ) == S_OK )
{
m_lSelectItemHook = Val;
m_bSelectItemHook = true;
g_lSelectItemHijackProc = HookCall( m_lSelectItemHook, (DWORD) SelectItemHook );
SetHookEx( eOnSelectItemEvent );
}
bool m_bUstAddItem = false;
bool m_bUstAddItem_Off1 = false;
bool m_bUstAddItem_Off2 = false;
if (QueryMemLoc(BSTRT( "UstAddItem" ), &Val) == S_OK)
{
m_lUstAddItem = Val;
m_bUstAddItem = true;
}
if (QueryMemLoc(BSTRT( "UstAddItem_Off1" ), &Val) == S_OK)
{
m_lUstAddItem_Off1 = Val;
m_bUstAddItem_Off1 = true;
}
if (QueryMemLoc(BSTRT( "UstAddItem_Off2" ), &Val) == S_OK)
{
m_lUstAddItem_Off2 = Val;
m_bUstAddItem_Off2 = true;
}
if (m_bUstAddItem && m_bUstAddItem_Off1 && m_bUstAddItem_Off2 && m_bChatMessageAddy)
{
SetHookEx(eUstAddItem);
m_bUstAddItem_Useable = true;
}
m_lRequestShortcircuit1 = 0;
m_lRequestShortcircuit2 = 0;
m_lRequestShortcircuit3 = 0;
if( QueryMemLoc( BSTRT( "RequestShortcircuit1" ), &Val ) == S_OK )
m_lRequestShortcircuit1 = Val;
if( QueryMemLoc( BSTRT( "RequestShortcircuit2" ), &Val ) == S_OK )
m_lRequestShortcircuit2 = Val;
if( QueryMemLoc( BSTRT( "RequestShortcircuit3" ), &Val ) == S_OK )
m_lRequestShortcircuit3 = Val;
if( m_lRequestShortcircuit1 && m_lRequestShortcircuit2 && m_lRequestShortcircuit3 )
{
DWORD dwHook1 = HookCall( m_lRequestShortcircuit1, (DWORD) IdentifyShortcircuit );
DWORD dwHook2 = HookCall( m_lRequestShortcircuit2, (DWORD) IdentifyShortcircuit );
DWORD dwHook3 = HookCall( m_lRequestShortcircuit3, (DWORD) IdentifyShortcircuit );
if( dwHook1 && dwHook2 && dwHook3 && (dwHook1 == dwHook2) && (dwHook2 == dwHook3) )
{
m_bRequestShortcircuit = true;
g_lIdentifyHijackProc = dwHook1;
}
else
{
// Something's wrong.
HookCall( m_lRequestShortcircuit1, dwHook1 );
HookCall( m_lRequestShortcircuit2, dwHook2 );
HookCall( m_lRequestShortcircuit3, dwHook3 );
}
}
if( QueryMemLoc( BSTRT( "IdleTime" ), &Val ) == S_OK )
{
m_lIdleLoc = Val;
m_bIdleLoc = true;
SetHookEx( eSetIdleTime );
}
if( QueryMemLoc( BSTRT( "SlashDay" ), &Val ) == S_OK )
{
m_lSlashDay = Val;
m_bSlashDay = true;
SetHookEx( eSetDay );
}
}
cACHooks::~cACHooks()
{
_bstr_t _Unnamed;
delete [] g_szTimestampFormat;
long Val, lCall1 = 0, lCall2 = 0;
if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call1"), &Val ) == S_OK )
{
lCall1 = Val;
}
if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call2"), &Val ) == S_OK )
{
lCall2 = Val;
}
if (lCall1 && lCall2)
{
HookCall( lCall1, g_lObjectDestroyedProc );
HookCall( lCall2, g_lObjectDestroyedProc );
}
if( m_bRequestShortcircuit )
{
HookCall( m_lRequestShortcircuit1, g_lIdentifyHijackProc );
HookCall( m_lRequestShortcircuit2, g_lIdentifyHijackProc );
HookCall( m_lRequestShortcircuit3, g_lIdentifyHijackProc );
}
if( m_bToolTextHook )
{
HookCall( m_lToolTextHJ, g_lToolTextProc );
}
if( m_bToolText2Hook )
{
HookCall( m_lToolText2HJ, g_lToolText2Proc );
}
s_pACHooks = NULL;
g_lObjectDestroyedProc = 0;
if( m_bDecalRef )
m_pDecal.Release();
if( m_bIdQueueRef )
m_pIdQueue.Release();
}
void cACHooks::DecryptXML( const char *szPath, std::string &szXML )
{
if( szPath == NULL )
{
szXML = "";
return;
}
FILE *f = fopen( szPath, "rb" );
if( f == NULL )
{
szXML = "";
return;
}
szXML.clear();
unsigned char szBuffer[1025];
try
{
CCryptProv crypt;
if( crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV ) == NTE_BAD_KEYSET )
crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV, CRYPT_NEWKEYSET );
CCryptMD5Hash hash;
hash.Initialize( crypt );
hash.AddString( DECAL_KEY );
CCryptDerivedKey key;
key.Initialize( crypt, hash );
DWORD dwDecLen = 0;
while( ! feof(f) )
{
memset( szBuffer, 0, sizeof( szBuffer ) );
dwDecLen = fread( szBuffer, 1, 1024, f );
key.Decrypt( feof(f), (BYTE *) szBuffer, &dwDecLen );
szXML += (char *)szBuffer;
}
key.Destroy();
hash.Destroy();
crypt.Release();
}
catch( ... )
{
// crap...
szXML = "";
}
fclose( f );
}
STDMETHODIMP cACHooks::SetDecal( IUnknown *pDecal )
{
if( m_bDecalRef )
{
m_pDecal.Release();
m_bDecalRef = false;
}
if( pDecal->QueryInterface( __uuidof( IDecal ), reinterpret_cast< void ** >( &m_pDecal ) ) == S_OK )
m_bDecalRef = true;
return S_OK;
}
STDMETHODIMP cACHooks::QueryMemLoc(BSTR bstrName, long *pVal)
{
USES_CONVERSION;
if( m_bMismatch )
{
*pVal = NULL;
return S_FALSE;
}
std::string queryName = OLE2A( bstrName );
LocMap::iterator i = m_mLocationList.find( queryName );
if( i != m_mLocationList.end() )
{
*pVal = i->second.Location;
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP cACHooks::get_CurrentSelection( long *pVal )
{
if( !m_bCurrentSelect )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lCurrentSelect[0] ) );
return S_OK;
}
STDMETHODIMP cACHooks::put_CurrentSelection(long newVal)
{
if( !m_bCurrentSelect )
return S_FALSE;
*( reinterpret_cast< long * >( m_lCurrentSelect[0] ) ) = newVal;
*( reinterpret_cast< long * >( m_lCurrentSelect[1] ) ) = newVal;
return S_OK;
}
STDMETHODIMP cACHooks::get_PreviousSelection(long *pVal)
{
if( !m_bPrevSelect )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lPrevSelect[0] ) );
return S_OK;
}
STDMETHODIMP cACHooks::put_PreviousSelection(long newVal)
{
if( !m_bPrevSelect )
return S_FALSE;
*( reinterpret_cast< long * >( m_lPrevSelect[0] ) ) = newVal;
*( reinterpret_cast< long * >( m_lPrevSelect[1] ) ) = newVal;
return S_OK;
}
/* Heyus - 23 March 2003 */
// Should be the method by which all functions write text to the chat window
// Writes raw text (does not append \n). chatMessageArg1 and 2 are the first two
// arguments you normally pass to pfnOldChatMessage. THIS SHOULD NOT BE CALLED BY
// PLUGINS/FILTERS UNLESS ABSOLUTELY NECESSARY.
// Will implement IKitchenSink later
void InternalRawWriteToChat( char* pText, long lColor, int chatMessageArg1, int chatMessageArg2 )
{
if( pText == NULL )
return;
if( g_bTimestamp )
{
bool bDoTimeStamp = (g_charBufferPreviousCall == '\n') ? true : false;
int iStrLen = strlen( pText );
char *szTimeStamp = new char[ iStrLen + 2 ];
memset( szTimeStamp, 0, iStrLen + 2 );
// Copy into a larger buffer to accomodate a possible \n
// If i were more awake, I'd see if this could just be replaced with
// g_charBufferPreviousCall = pText[strlen(pText)]
int iOffset = 0;
char *szTemp = pText;
while( *szTemp != 0 )
{
szTimeStamp[ iOffset++ ] = *szTemp;
g_charBufferPreviousCall = *szTemp;
szTemp++;
}
// Format a time stamp
char szFormattedTimestamp[ MAX_PATH ];
memset( szFormattedTimestamp, 0, MAX_PATH );
time_t stTmpTime;
time( &stTmpTime );
tm *tmTime = localtime( &stTmpTime );
long lFormattedStampLength = (long) strftime( szFormattedTimestamp, MAX_PATH, g_szTimestampFormat, tmTime );
while( *szTimeStamp != NULL && *szTimeStamp == '\n' )
{
pfnOldChatMessage( chatMessageArg1, chatMessageArg2, "\n", lColor );
g_charBufferPreviousCall = '\n';
*szTimeStamp++;
}
char* szToken = strtok( szTimeStamp, _T( "\n" ) );
char* toWrite;
if( g_lTimestampColor != 0xFFFFFFFF )
lFormattedStampLength = 0;
while( szToken != NULL )
{
int len = strlen( szToken ) + lFormattedStampLength + 3;
toWrite = new char[ len ];
memset( toWrite, 0, len );
if( bDoTimeStamp )
{
if( g_lTimestampColor == 0xFFFFFFFF )
toWrite = strcat( toWrite, szFormattedTimestamp );
else
pfnOldChatMessage( chatMessageArg1, chatMessageArg2, szFormattedTimestamp, g_lTimestampColor );
}
toWrite = strcat( toWrite, szToken );
char* nextToken = strtok( NULL, "\n" );
if( nextToken != NULL || pText[strlen(pText)-1] == '\n' )
toWrite = strcat( toWrite, "\n" );
pfnOldChatMessage( chatMessageArg1, chatMessageArg2, toWrite, lColor );
szToken = nextToken;
delete[] toWrite;
}
delete[] szTimeStamp;
}
else
pfnOldChatMessage( chatMessageArg1, chatMessageArg2, pText, lColor );
return;
}
STDMETHODIMP cACHooks::ChatOut(BSTR szText, long lColor)
{
if( pfnOldChatMessage == NULL )
return S_FALSE;
DWORD *Addy = reinterpret_cast< DWORD * > ( m_lChatMessageAddy );
if( *Addy == NULL )
return S_FALSE;
USES_CONVERSION;
char *strText = OLE2A( szText );
if( strText == NULL )
return S_FALSE;
int iStrLen = strlen( strText );
int iOffset = 0;
char* szTemp = new char[iStrLen + 2];
memset( szTemp, 0, iStrLen+2 );
strncpy( szTemp, strText, iStrLen + 2 );
strncat( szTemp, "\n", iStrLen + 2 );
InternalRawWriteToChat( szTemp, lColor, *Addy, 0 );
return S_OK;
}
/* Heyus - 23 Mar 2003 - Fixed to point to the new universal function */
STDMETHODIMP cACHooks::RawChatOut(BSTR szText, long lColor)
{
if( pfnOldChatMessage == NULL )
return S_FALSE;
DWORD *Addy = reinterpret_cast< DWORD * > ( m_lChatMessageAddy );
if( *Addy == NULL )
return S_FALSE;
USES_CONVERSION;
char *strText = OLE2A( szText );
InternalRawWriteToChat( strText, lColor, *Addy, 0 );
return S_OK;
}
STDMETHODIMP cACHooks::SetCursorPosition(long lX, long lY)
{
if( !m_bMouse )
return S_FALSE;
for( int i = 0; i < 4; i++ )
{
*(reinterpret_cast< long * >( m_lMouse[i] ) ) = lX;
*(reinterpret_cast< long * >( m_lMouse[i] + 4 ) ) = lY;
}
SetCursorPos( lX, lY );
for( i = 0; i < 4; i++ )
{
*(reinterpret_cast< long * >( m_lMouse[i] ) ) = lX;
*(reinterpret_cast< long * >( m_lMouse[i] + 4 ) ) = lY;
}
return S_OK;
}
STDMETHODIMP cACHooks::CastSpell(long lSpellID, long lObjectID)
{
if( !m_bCastSpell )
return S_FALSE;
long lCombatState = 4;
if( get_CombatState( &lCombatState ) == S_OK )
{
if( lCombatState != 4 ) //Must be in MAGIC MODE
return S_FALSE;
}
long lCurrentSelect;
get_CurrentSelection( &lCurrentSelect );
put_CurrentSelection( lObjectID );
typedef void(*CastPtr)( long );
CastPtr pCast = reinterpret_cast< CastPtr >( m_lCastSpell );
pCast( lSpellID );
put_CurrentSelection( lCurrentSelect );
return S_OK;
}
STDMETHODIMP cACHooks::MoveItem(long lObjectID, long lPackID, long lSlot, VARIANT_BOOL bStack)
{
if( !m_bMoveItem )
return S_FALSE;
long lStack = 0;
if( bStack == VARIANT_TRUE )
lStack = 1;
typedef void(*MovePtr)( long, long, long, long );
MovePtr pMove = reinterpret_cast< MovePtr >( m_lMoveItem );
pMove( lObjectID, lPackID, lSlot, lStack );
return S_OK;
}
STDMETHODIMP cACHooks::SelectItem(long lObjectID)
{
if( !m_bSelectItem )
return S_FALSE;
typedef void(*SelectPtr)( long );
SelectPtr pSelect = reinterpret_cast< SelectPtr >( m_lSelectItem );
pSelect( lObjectID );
return S_OK;
}
STDMETHODIMP cACHooks::UseItem(long lObjectID, long lUseState)
{
if( !m_bUseItem )
return S_FALSE;
__asm
{
push 0x0
push lUseState
push lObjectID
call pfnUseItem
add esp, 0x0C
}
return S_OK;
}
STDMETHODIMP cACHooks::UseItemRaw(long lObjectID, long lUseState, long lUseMethod)
{
if( !m_bUseItem )
return S_FALSE;
__asm
{
push lUseMethod
push lUseState
push lObjectID
call pfnUseItem
add esp, 0x0C
}
return S_OK;
}
STDMETHODIMP cACHooks::UseFociSpell(long UseThis, long OnThis)
{
if( !m_bUseItem )
return S_FALSE;
long lCurrentSelected;
get_CurrentSelection( &lCurrentSelected );
put_CurrentSelection( OnThis );
__asm
{
push 0x1
push 0x1
push UseThis
call pfnUseItem
add esp, 0x0C
}
put_CurrentSelection( lCurrentSelected );
return S_OK;
}
STDMETHODIMP cACHooks::get_CombatState(long *pVal)
{
if( !m_bAllYourBase )
return S_FALSE;
if( !m_bCombatStateOffset )
return S_FALSE;
*pVal = *(reinterpret_cast< long * >( (*reinterpret_cast< char ** >( m_lAllYourBase )) + m_lCombatStateOffset ));
return S_OK;
}
STDMETHODIMP cACHooks::SetCombatState(long pVal)
{
if( !m_bSetCombatState )
return S_FALSE;
if( (pVal < 1) || (pVal > 4) )
return E_INVALIDARG;
typedef void(__fastcall *SetCombatStatePtr)( long, long, long, long );
SetCombatStatePtr pSetCState = reinterpret_cast< SetCombatStatePtr >( m_lSetCombatState );
pSetCState( *( reinterpret_cast< long * >( m_lAllYourBase ) ), 0, pVal, 1 );
return S_OK;
}
STDMETHODIMP cACHooks::get_ChatState(VARIANT_BOOL *pVal)
{
if( !m_bChatState )
return S_FALSE;
long *pChatState = reinterpret_cast< long * >( m_lChatState );
if( m_bDecalRef )
{
CComPtr< IPSite > pSite;
if( m_pDecal->get_Object( _bstr_t( "services\\DecalPlugins.InjectService\\site" ), __uuidof( IPSite ), reinterpret_cast< void ** >( &pSite ) ) == S_OK )
{
if( pSite->get_Focus( pVal ) != S_OK )
*pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE;
else
*pVal = (*pChatState || (*pVal == VARIANT_TRUE) ) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
else
*pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
*pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP cACHooks::UseItemEx(long UseThis, long OnThis)
{
if( !m_bUseItem )
return S_FALSE;
long lCurrentSelected;
get_CurrentSelection( &lCurrentSelected );
put_CurrentSelection( OnThis );
UseItem( UseThis, 1 );
put_CurrentSelection( lCurrentSelected );
return S_OK;
}
STDMETHODIMP cACHooks::GetFellowStats(long lCharID)
{
return IDQueueAdd( lCharID );
}
STDMETHODIMP cACHooks::get_SelectedStackCount(long lStackCount, long *pVal)
{
if( !m_bStackCount )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lStackCount ) );
return S_OK;
}
STDMETHODIMP cACHooks::put_SelectedStackCount(long lStackCount, long newVal)
{
if( !m_bStackCount )
return S_FALSE;
*( reinterpret_cast< long * >( m_lStackCount ) ) = newVal;
return S_OK;
}
STDMETHODIMP cACHooks::get_VendorID(long *pVal)
{
if( !m_bVendorID )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lVendorID ) );
return S_OK;
}
STDMETHODIMP cACHooks::get_BusyState(long *pVal)
{
if( !m_bBusyState )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lBusyState ) );
return S_OK;
}
STDMETHODIMP cACHooks::get_BusyStateID(long *pVal)
{
if( !m_bBusyStateID )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lBusyStateID ) );
return S_OK;
}
STDMETHODIMP cACHooks::get_PointerState(long *pVal)
{
if( !m_bPointerState )
return S_FALSE;
*pVal = *( reinterpret_cast< long * >( m_lPointerState ) );
return S_OK;
}
STDMETHODIMP cACHooks::MoveItemEx(long lObjectID, long lDestinationID)
{
if( !m_bMoveItemEx )
return S_FALSE;
__asm
{
push 0x0
push lDestinationID
push lObjectID
call pfnMoveItemEx
add esp, 0x0C
}
return S_OK;
}
long* cACHooks::GetCs(long offs)
{
if (!m_bAllYourBase) {
return NULL ;
}
// follow multiple indirection from m_lCombatState to the
long *rv = reinterpret_cast< long * >( m_lAllYourBase );
if (*rv) rv = reinterpret_cast< long * >( *rv + 0xE4 );
if (*rv) rv = reinterpret_cast< long * >( *rv + 0x160 );
if (*rv) rv = reinterpret_cast< long * >( *rv + offs);
return rv ;
}
STDMETHODIMP cACHooks::get_Heading(double *pVal)
{
HRESULT rv = S_OK ;
if (!m_bAllYourBase) {
*pVal = 0.0 ;
return S_FALSE ;
}
long* pX = GetCs(0x6C) ;
long* pY = GetCs(0x70) ;
float fHeadingX(0) ;
float fHeadingY(0) ;
if (pX) {
fHeadingX = *(reinterpret_cast< float * >(pX)) ;
} else {
rv = S_FALSE ;
}
if (pY) {
fHeadingY = *(reinterpret_cast< float * >(pY)) ;
} else {
rv = S_FALSE ;
}
long lCardinal = 0;
if( (fHeadingX > 0) && (fHeadingY > 0) )
lCardinal = 90;
if( (fHeadingX < 0) && (fHeadingY < 0) )
lCardinal = 270;
if( (fHeadingX < 0) && (fHeadingY > 0) )
lCardinal = 270;
if( (fHeadingX > 0) && (fHeadingY < 0) )
lCardinal = 450;
*pVal = fabs( atan( fHeadingY / fHeadingX ) * 180 / 3.14159265358979323846 - 450 + lCardinal );
return rv;
}
STDMETHODIMP cACHooks::get_Landblock(long *pVal)
{
HRESULT rv = S_OK ;
*pVal = 0 ;
if (!m_bAllYourBase) {
return S_FALSE ;
}
long *cs = GetCs(0x4C) ;
if (cs) {
*pVal = *cs ;
} else {
*pVal = rv ;
}
return rv;
}
STDMETHODIMP cACHooks::get_LocationX(double *pVal)
{
HRESULT rv = S_OK ;
if (!m_bAllYourBase) {
*pVal = 0 ;
return S_FALSE ;
}
long* cs = GetCs(0x50) ;
float val(0) ;
if (cs) {
val = *(reinterpret_cast< float * >(cs));
} else {
rv = S_FALSE ;
}
*pVal = double(val) ;
return rv;
}
STDMETHODIMP cACHooks::get_LocationY(double *pVal)
{
HRESULT rv = S_OK ;
if (!m_bAllYourBase) {
*pVal = 0 ;
return S_FALSE ;
}
long* cs = GetCs(0x54) ;
float val(0) ;
if (cs) {
val = *(reinterpret_cast< float * >(cs));
} else {
rv = S_FALSE ;
}
*pVal = double(val) ;
return rv;
}
STDMETHODIMP cACHooks::get_LocationZ(double *pVal)
{
HRESULT rv = S_OK ;
if (!m_bAllYourBase) {
*pVal = 0 ;
return S_FALSE ;
}
long* cs = GetCs(0x58) ;
float val(0) ;
if (cs) {
val = *(reinterpret_cast< float * >(cs));
} else {
rv = S_FALSE ;
}
*pVal = double(val) ;
return rv ;
}
STDMETHODIMP cACHooks::get_HooksAvail(long *pVal) {
*pVal = m_Hooks ;
return S_OK ;
}
STDMETHODIMP cACHooks::DropItem(long lObjectID)
{
if( !m_bMoveItemEx )
return S_FALSE;
__asm
{
push 0x1
push 0x0
push lObjectID
call pfnMoveItemEx
add esp, 0x0C
}
return S_OK;
}
// Turn to a particular heading, discovered by Madar on 8/25/2002
STDMETHODIMP cACHooks::FaceHeading (float fHeading, VARIANT_BOOL bUnknown, VARIANT_BOOL *pRetval)
{
if (!m_bFaceHeading)
{
*pRetval = VARIANT_FALSE;
return S_FALSE;
}
DWORD dwTemp = m_lFaceHeading;
DWORD ** pTemp = (DWORD **) m_lMovementThingyParent;
DWORD dwMovementThingy = pTemp[0][m_lMovementThingyOffset];
long lResult = 0;
DWORD dwSecondArg = (bUnknown == VARIANT_TRUE) ? 1 : 0;
__asm
{
mov ecx,dwMovementThingy
push dwSecondArg
push fHeading
call dwTemp
mov lResult, eax
}
*pRetval = lResult ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
// Set auto-run, discovered by Madar on 9/16/2002
STDMETHODIMP cACHooks::SetAutorun (VARIANT_BOOL bOnOff)
{
if (!m_bSetAutorun)
{
return S_FALSE;
}
DWORD dwTemp = m_lSetAutorun;
DWORD ** pTemp = (DWORD **) m_lMovementThingyParent;
DWORD dwMovementThingy = pTemp[0][m_lMovementThingyOffset];
long lFirstArg = (bOnOff == VARIANT_TRUE) ? 1 : 0;
long lUnknown = 1;
__asm
{
mov ecx,dwMovementThingy
push lUnknown
push lFirstArg
call dwTemp
}
return S_OK;
}
STDMETHODIMP cACHooks::ItemIsKnown(long lGUID, VARIANT_BOOL* pRetval)
{
if (!m_bObjectFromGuid)
{
*pRetval = VARIANT_FALSE;
return S_FALSE;
}
DWORD dwTemp = m_lObjectFromGuid ;
DWORD dwClass = *((DWORD*) m_lObjectFromGuidClass);
long lResult = 0;
__asm
{
mov ecx,dwClass
push lGUID
call dwTemp
mov lResult, eax
}
*pRetval = lResult ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP cACHooks::get_Area3DWidth(long *pVal)
{
if( !m_bArea3DWidth )
return S_FALSE;
*pVal = *m_lpArea3DWidth;
return S_OK;
}
STDMETHODIMP cACHooks::get_Area3DHeight(long *pVal)
{
if( !m_bArea3DHeight )
return S_FALSE;
*pVal = *m_lpArea3DHeight;
return S_OK;
}
STDMETHODIMP cACHooks::SendTell( long lPlayerID, BSTR Message )
{
if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToID) )
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( Message );
long retval;
qString Msg;
pfnInternalStringConstructor( &Msg, 0, szText );
retval = pfnSendMessageToID( &Msg, lPlayerID );
pfnInternalStringDestructor( &Msg );
return S_OK;
}
STDMETHODIMP cACHooks::SendTellEx( BSTR Name, BSTR Message )
{
if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToName) )
return S_FALSE;
USES_CONVERSION;
char *szName = OLE2A( Name );
char *szText = OLE2A( Message );
long retval;
qString qSName;
qString qSMsg;
pfnInternalStringConstructor( &qSMsg, 0, szText );
pfnInternalStringConstructor( &qSName, 0, szName );
retval = pfnSendMessageToName( &qSMsg, &qSName );
pfnInternalStringDestructor( &qSMsg );
pfnInternalStringDestructor( &qSName );
return S_OK;
}
STDMETHODIMP cACHooks::LocalChatText(BSTR Text)
{
if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatText) )
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( Text );
qString qSText;
pfnInternalStringConstructor( &qSText, 0, szText );
pfnLocalChatText( &qSText );
pfnInternalStringDestructor( &qSText );
return S_OK;
}
STDMETHODIMP cACHooks::LocalChatEmote(BSTR EmoteText)
{
if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatEmote) )
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( EmoteText );
qString qSText;
pfnInternalStringConstructor( &qSText, 0, szText );
pfnLocalChatEmote( &qSText );
pfnInternalStringDestructor( &qSText );
return S_OK;
}
STDMETHODIMP cACHooks::get_Vital(long Vital, long* pVal)
{
if( !(m_bGetVital && m_lVitalBase) )
return S_FALSE;
if( (Vital < 1) || (Vital > 9) )
return E_INVALIDARG;
long lBaseOrBuffed = (Vital > 6) ? 1 : 0;
if( lBaseOrBuffed )
{
if( Vital == 7 ) // health
Vital = 2;
else if( Vital == 8 ) // stamina
Vital = 4;
else if( Vital == 9 ) // mana
Vital = 6;
}
long ( __fastcall *Internal_GetStat )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetVital );
qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase );
p = p->dd[0];
Internal_GetStat( p, 0, Vital, pVal, lBaseOrBuffed );
return S_OK;
}
STDMETHODIMP cACHooks::get_Attribute(long Attribute, long* pVal)
{
if( !(m_bGetAttribute && m_lVitalBase) )
return S_FALSE;
if( (Attribute < 1) || (Attribute > 12) )
return E_INVALIDARG;
long lBaseOrBuffed = (Attribute > 6) ? 1 : 0;
if( lBaseOrBuffed )
Attribute -= 6;
qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase );
p = p->dd[0];
long ( __fastcall *Internal_GetAttribute )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetAttribute );
Internal_GetAttribute( p, 0, Attribute, pVal, lBaseOrBuffed );
return S_OK;
}
STDMETHODIMP cACHooks::get_Skill(long Skill, long* pVal)
{
if( !(m_bGetSkill && m_lVitalBase) )
return S_FALSE;
// error on out of range, the unused range for added skills, and other skill ids that Turbine skips
if((Skill < 1) || (Skill > 89) || ((Skill > 39) && (Skill < 50)) || (Skill == 8 ) || (Skill == 58) || (Skill == 17) || (Skill == 67) || (Skill == 25) || (Skill == 75) || (Skill == 26) || (Skill == 76))
return E_INVALIDARG;
long lBaseOrBuffed = (Skill > 50) ? 1 : 0;
if( lBaseOrBuffed )
Skill -= 50;
qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase );
p = p->dd[0];
long ( __fastcall *Internal_GetSkill )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetSkill );
Internal_GetSkill( p, 0, Skill, pVal, lBaseOrBuffed );
return S_OK;
}
STDMETHODIMP cACHooks::get_HooksAvailEx(eAvailableHooksEx HookID, VARIANT_BOOL *pVal)
{
unsigned int ID;
unsigned int Index, Offset;
// Default to not being valid
*pVal = VARIANT_FALSE;
// Convert the enum to an integer so we can do maths on it
ID = static_cast< unsigned int >( HookID );
// Ensure the value is within range
if( ID > m_HookCount )
{
return S_OK;
}
// Extract the index and bit offset
Index = ID >> 5; // 32 -> 5 bits
Offset = ID & 0x1F; // 1F -> 5 bits worth of 1s
if( m_HooksEx[Index] & (1 << Offset) )
{
*pVal = VARIANT_TRUE;
}
return S_OK;
}
STDMETHODIMP cACHooks::Logout()
{
if( m_bLogout )
{
long ( __cdecl *Internal_Logout )( long );
Internal_Logout = reinterpret_cast< long ( __cdecl * )( long ) >( m_lLogout );
Internal_Logout(0);
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP cACHooks::ToolText(BSTR Text, VARIANT_BOOL bError)
{
/*
Moputu - 09012003: Added to allow plugins to display text
in the upper left hand corner as either white text w/o sound or
as yellow text with the busy/error sound.
Either CombatState or ObjectBase can be used as the starting
memloc as both always seems to have the same value and the
function is called using one or the other in the client.exe.
You can only find the function address after the player is logged in.
*/
if( !m_bAllYourBase ) //the combat state memloc is necessary
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( Text ); //pointer to the text being passed
DWORD cstate = *((long *)m_lAllYourBase);
long lErr;
if (bError)
lErr = 1; // display text as yellow w/sound
else
lErr = 0; // display text as white w/o sound
__asm
{
mov ecx, cstate
push lErr
push szText
mov edx, dword ptr [ecx]
call dword ptr [edx+114h]
add esp, 8
}
return S_OK;
}
STDMETHODIMP cACHooks::ToolTextAppend(BSTR Text, VARIANT_BOOL bError)
{
if( !m_bAllYourBase ) //the combat state memloc is necessary
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( Text ); //pointer to the text being passed
DWORD cstate = *((long *)m_lAllYourBase);
long lErr;
if (bError)
lErr = 1; // display text as yellow w/sound
else
lErr = 0; // display text as white w/o sound
__asm
{
mov ecx, cstate
push lErr
push szText
mov edx, dword ptr [ecx]
call dword ptr [edx+118h]
}
return S_OK;
}
STDMETHODIMP cACHooks::SecureTrade_Add(long ItemID, VARIANT_BOOL *pVal)
{
void ( __fastcall *Internal_SecureTrade_Add )( struct qPointerList *, int, long );
struct qPointerList *p;
VARIANT_BOOL ItemExists;
if (pVal) /* Should probably return an error code. Tough. */
{
*pVal = VARIANT_FALSE;
}
else
return E_FAIL;
if ( m_bSecureTrade_Add && m_bSecureTrade_Add_Off1 && m_bSecureTrade_Add_Off2 && m_bAllYourBase )
{
if( ItemIsKnown(ItemID, &ItemExists) != S_OK )
return E_FAIL;
if (ItemExists == VARIANT_FALSE)
{
return S_FALSE;
}
p = (qPointerList *)m_lAllYourBase;
if (!p)
{
return S_FALSE;
}
p = p->dd[0];
if (!p)
{
return S_FALSE;
}
p = p->dd[m_lSecureTrade_Add_Off1 >> 2];
if (!p)
{
return S_FALSE;
}
p = p->dd[m_lSecureTrade_Add_Off2 >> 2];
if (!p)
{
return S_FALSE;
}
Internal_SecureTrade_Add = reinterpret_cast< void ( __fastcall *)( struct qPointerList *, int, long ) >( m_lSecureTrade_Add );
Internal_SecureTrade_Add(p, 0, ItemID);
if (pVal)
{
*pVal = VARIANT_TRUE;
}
return S_OK;
}
return S_FALSE;
}
HRESULT cACHooks::GetSkillInfo(eSkill SkillID, struct qSkill *Skill) {
int ( __fastcall *Internal_GetSkillInfo )( void *, int, int, struct qSkill * );
if (!m_bGetSkillInfo) {
return E_FAIL;
}
if (SkillID > 50) {
SkillID = (eSkill)(SkillID - 50);
}
if ((SkillID < 1) || (SkillID > 50)) {
return E_INVALIDARG;
}
Skill->vTable = m_lGetSkillInfo_vT;
Internal_GetSkillInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qSkill *) >(m_lGetSkillInfo);
if (Internal_GetSkillInfo(*(void **)m_lVitalBase, 0, SkillID, Skill)) {
return S_OK;
}
return E_FAIL;
}
HRESULT cACHooks::GetAttributeInfo(eAttribute AttributeID, struct qAttribute *Attribute) {
int (__fastcall *Internal_GetAttributeInfo)(void *, int, int, struct qAttribute *);
if (!m_bGetAttributeInfo) {
return E_FAIL;
}
if (AttributeID > 6) {
AttributeID = (eAttribute)(AttributeID - 6);
}
if ((AttributeID < 1) || (AttributeID > 6)) {
return E_INVALIDARG;
}
Attribute->vTable = m_lGetAttributeInfo_vT;
Internal_GetAttributeInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qAttribute *) >(m_lGetAttributeInfo);
if (Internal_GetAttributeInfo(*(void **)m_lVitalBase, 0, AttributeID, Attribute)) {
return S_OK;
}
return E_FAIL;
}
HRESULT cACHooks::GetVitalInfo(eVital VitalID, struct qVital *Vital) {
int (__fastcall *Internal_GetVitalInfo)(void *, int, int, struct qVital *);
if (!m_bGetVitalInfo) {
return E_FAIL;
}
switch (VitalID) {
case eCurrentHealth:
case eMaximumHealth:
case eBaseHealth:
VitalID = eCurrentHealth;
break;
case eCurrentStamina:
case eMaximumStamina:
case eBaseStamina:
VitalID = eCurrentStamina;
break;
case eCurrentMana:
case eMaximumMana:
case eBaseMana:
VitalID = eCurrentMana;
break;
default:
return E_INVALIDARG;
}
Vital->vTable = m_lGetVitalInfo_vT;
Internal_GetVitalInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qVital *) >(m_lGetVitalInfo);
if (Internal_GetVitalInfo(*(void **)m_lVitalBase, 0, VitalID, Vital)) {
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP cACHooks::get_SkillTrainLevel( eSkill SkillID, eTrainLevel *pVal )
{
struct qSkill Skill;
HRESULT hr;
hr = GetSkillInfo(SkillID, &Skill);
if (FAILED(hr)) {
return hr;
}
*pVal = Skill.Trained;
return S_OK;
}
STDMETHODIMP cACHooks::get_SkillTotalXP( eSkill SkillID, int *pVal )
{
struct qSkill Skill;
HRESULT hr;
hr = GetSkillInfo(SkillID, &Skill);
if (FAILED(hr)) {
return hr;
}
*pVal = Skill.TotalXP;
return S_OK;
}
STDMETHODIMP cACHooks::get_SkillFreePoints( eSkill SkillID, int *pVal )
{
struct qSkill Skill;
HRESULT hr;
hr = GetSkillInfo(SkillID, &Skill);
if (FAILED(hr)) {
return hr;
}
*pVal = Skill.FreePoints;
return S_OK;
}
STDMETHODIMP cACHooks::get_SkillClicks( eSkill SkillID, int *pVal )
{
struct qSkill Skill;
HRESULT hr;
hr = GetSkillInfo(SkillID, &Skill);
if (FAILED(hr)) {
return hr;
}
*pVal = Skill.Clicks;
return S_OK;
}
STDMETHODIMP cACHooks::get_AttributeClicks( eAttribute AttributeID, int *pVal )
{
struct qAttribute Attribute;
HRESULT hr;
hr = GetAttributeInfo(AttributeID, &Attribute);
if (FAILED(hr)) {
return hr;
}
*pVal = Attribute.Clicks;
return S_OK;
}
STDMETHODIMP cACHooks::get_AttributeTotalXP( eAttribute AttributeID, int *pVal )
{
struct qAttribute Attribute;
HRESULT hr;
hr = GetAttributeInfo(AttributeID, &Attribute);
if (FAILED(hr)) {
return hr;
}
*pVal = Attribute.TotalXP;
return S_OK;
}
STDMETHODIMP cACHooks::get_AttributeStart( eAttribute AttributeID, int *pVal )
{
struct qAttribute Attribute;
HRESULT hr;
hr = GetAttributeInfo(AttributeID, &Attribute);
if (FAILED(hr)) {
return hr;
}
*pVal = Attribute.Start;
return S_OK;
}
STDMETHODIMP cACHooks::get_VitalClicks( eVital VitalID, int *pVal )
{
struct qVital Vital;
HRESULT hr;
hr = GetVitalInfo(VitalID, &Vital);
if (FAILED(hr)) {
return hr;
}
*pVal = Vital.Clicks;
return S_OK;
}
STDMETHODIMP cACHooks::get_VitalTotalXP( eVital VitalID, int *pVal )
{
struct qVital Vital;
HRESULT hr;
hr = GetVitalInfo(VitalID, &Vital);
if (FAILED(hr)) {
return hr;
}
*pVal = Vital.TotalXP;
return S_OK;
}
void cACHooks::SetHookEx( eAvailableHooksEx HookID )
{
unsigned int ID;
unsigned int Index, Offset;
ID = static_cast< unsigned int >( HookID );
Index = ID >> 5;
Offset = ID & 0x1F;
_ASSERTE( Index < (sizeof(m_HooksEx) / sizeof(m_HooksEx[0])) );
m_HooksEx[Index] |= (1 << Offset);
if( ID > m_HookCount )
m_HookCount = ID;
return;
}
STDMETHODIMP cACHooks::SetIdleTime( double dIdleTimeout )
{
if( !m_bIdleLoc )
return S_FALSE;
DWORD dwOldProtect = 0;
DWORD dwNewProtect = PAGE_READWRITE;
VirtualProtect( reinterpret_cast< void * >( m_lIdleLoc ), 8 /* sizeof double */, dwNewProtect, &dwOldProtect );
*( reinterpret_cast< double * >( m_lIdleLoc ) ) = dIdleTimeout;
VirtualProtect( reinterpret_cast< void * >( m_lIdleLoc ), 8 /* sizeof double */, dwOldProtect, &dwNewProtect );
return S_OK;
}
void cACHooks::InternalObjectDestroyed (DWORD dwGuid)
{
Fire_ObjectDestroyed( dwGuid );
}
void cACHooks::InternalSelectItem( DWORD dwID )
{
Fire_OnSelectItem( dwID );
}
void cACHooks::InternalShortcircuit( DWORD dwID )
{
if( m_bIdQueueRef )
m_pIdQueue->ShortcircuitID( dwID );
}
void OnObjectDestroyed (DWORD dwGuid)
{
if( cACHooks::s_pACHooks )
cACHooks::s_pACHooks->InternalObjectDestroyed( dwGuid );
}
void OnSelectItem( DWORD dwID )
{
if( cACHooks::s_pACHooks )
cACHooks::s_pACHooks->InternalSelectItem( dwID );
}
void Shortcircuit( DWORD dwID )
{
if( cACHooks::s_pACHooks )
cACHooks::s_pACHooks->InternalShortcircuit( dwID );
}
void __declspec(naked) SelectItemHook()
{
_asm
{
push eax
call OnSelectItem
add esp,4
jmp g_lSelectItemHijackProc
}
}
void __declspec(naked) ObjectDestroyedHook()
{
_asm
{
mov eax,[esp+8]
push eax
push ecx
push eax
call OnObjectDestroyed
add esp,4
pop ecx
pop eax
mov [esp+8],eax
jmp g_lObjectDestroyedProc
}
}
void __declspec(naked) IdentifyShortcircuit()
{
__asm
{
mov eax,[esp+4]
push eax
push ecx
push eax
call Shortcircuit
add esp, 4
pop ecx
pop eax
mov [esp+4], eax
jmp g_lIdentifyHijackProc
}
}
// Returns the function which previously was being called, after replacing it with the new call.
DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement)
{
DWORD* pTemp = (DWORD *) (dwCallAddress + 1);
HANDLE hProcess = OpenProcess
(
PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
FALSE,
GetCurrentProcessId ()
);
DWORD dwOriginal = 0;
if (hProcess)
{
dwOriginal = (*pTemp) + dwCallAddress + 5;
DWORD dwTemp = dwReplacement - (dwCallAddress + 5);
if (WriteProcessMemory
(
hProcess,
pTemp,
&dwTemp,
sizeof (DWORD),
NULL
))
{
}
else
{
dwOriginal = 0;
}
CloseHandle (hProcess);
}
return dwOriginal;
}
bool cACHooks::InternalChatMessage( char *szText, long lColor )
{
return Fire_OnChatBoxMessage( _bstr_t( szText ), lColor ) == VARIANT_TRUE ? true : false;
}
bool cACHooks::InternalChatText( char *szText )
{
return Fire_OnCommandLineText( _bstr_t( szText ) ) == VARIANT_TRUE ? true : false;
}
bool DispatchChatMessage( char *pText, long pdwColor )
{
if( cACHooks::s_pACHooks )
return cACHooks::s_pACHooks->InternalChatMessage( pText, pdwColor );
return false;
}
bool DispatchChatText( char *pText )
{
if( cACHooks::s_pACHooks )
return cACHooks::s_pACHooks->InternalChatText( pText );
return false;
}
/* Heyus - 23 Mar 2003 - Fixed to point to the new universal function */
void __fastcall OnChatMessage( int _ecx, int _edx, char* pText, long lColor )
{
if( !DispatchChatMessage( pText, lColor ) )
InternalRawWriteToChat( pText, lColor, _ecx, _edx );
return;
}
void __declspec(naked) OnChatText()
{
__asm
{
push ebp
mov ebp, esp
sub esp, 0xC
call pfnOldChatText
mov [ebp-4], ecx
mov [ebp-8], eax
push eax
call DispatchChatText
mov edx, eax
mov ecx, [ebp-4]
mov eax, [ebp-8]
test dl, dl
jz dont_eat_chat_text
mov byte ptr [eax], 0
dont_eat_chat_text:
mov esp, ebp
pop ebp
ret
}
}
void cACHooks::InternalToolText( char *szText, VARIANT_BOOL bError )
{
USES_CONVERSION;
Fire_OnToolText( T2BSTR( szText ), bError );
}
void OnToolText( char *szText, long lError )
{
VARIANT_BOOL bError = lError;
if( cACHooks::s_pACHooks )
cACHooks::s_pACHooks->InternalToolText( szText, bError );
}
void __declspec(naked) CatchToolText()
{
__asm
{
push ecx
push edx
push edi
push eax
call OnToolText
pop eax
pop edi
pop edx
pop ecx
jmp g_lToolTextProc
}
}
void cACHooks::InternalToolTextAppend( char *szText, VARIANT_BOOL bError )
{
USES_CONVERSION;
Fire_OnToolTextAppend( T2BSTR( szText ), bError );
}
void OnToolTextAppend( char *szText, long lError )
{
VARIANT_BOOL bError = lError;
if( cACHooks::s_pACHooks )
cACHooks::s_pACHooks->InternalToolTextAppend( szText, bError );
}
void __declspec(naked) CatchToolTextAppend()
{
__asm
{
push ecx
push edx
push edi
push eax
call OnToolTextAppend
pop eax
pop edi
pop edx
pop ecx
jmp g_lToolText2Proc
}
}
STDMETHODIMP cACHooks::RequestID(long lObjectID)
{
if( !m_bRequestID )
return S_FALSE;
if( m_bIdQueueRef )
return m_pIdQueue->AddToQueue( lObjectID );
typedef void(*RequestPtr)( long );
RequestPtr pRequest = reinterpret_cast< RequestPtr >( m_lRequestID );
pRequest( lObjectID );
return S_OK;
}
STDMETHODIMP cACHooks::IDQueueAdd(long lObjectID)
{
if( !m_bIdQueueRef )
return RequestID( lObjectID );
return m_pIdQueue->AddToQueue( lObjectID );
}
STDMETHODIMP cACHooks::SetIDFilter(IKitchenSink* pIDFilter)
{
if( !m_bIdQueueRef )
{
m_bIdQueueRef = true;
m_pIdQueue = pIDFilter;
SetHookEx( eIDQueueAdd );
}
return S_OK;
}
STDMETHODIMP cACHooks::UstAddItem(long lObjectID)
{
VARIANT_BOOL ItemExists;
if ( !m_bUstAddItem_Useable )
return S_FALSE;
if( ItemIsKnown( lObjectID, &ItemExists ) != S_OK )
return E_FAIL;
if( ItemExists == VARIANT_FALSE )
return S_FALSE;
//Calculate the THIS pointer
//DWORD thisPtr = *((long *)(*((long *)(*((long *)0x77A618) + 0x324)) + 0xE0));
//DWORD tmp;
//DWORD func = 0x005556C0;
DWORD thisPtr = *((long *)(*((long *)(*((long *)m_lChatMessageAddy) + m_lUstAddItem_Off1)) + m_lUstAddItem_Off2));
DWORD tmp;
DWORD func = (DWORD)m_lUstAddItem;
__asm
{
mov tmp, ecx
mov ecx, thisPtr
push lObjectID
call func
mov ecx, tmp
}
return S_OK;
}
STDMETHODIMP cACHooks::SendMessageByMask( long lMask, BSTR szMessage )
{
if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToMask) )
return S_FALSE;
USES_CONVERSION;
char *szText = OLE2A( szMessage );
long retval;
qString Msg;
pfnInternalStringConstructor( &Msg, 0, szText );
retval = pfnSendMessageByMask( lMask, &Msg );
pfnInternalStringDestructor( &Msg );
return S_OK;
}
STDMETHODIMP cACHooks::SetDay( VARIANT_BOOL bDay )
{
if( !m_bSlashDay )
return S_FALSE;
*reinterpret_cast< long * >( m_lSlashDay ) = bDay == VARIANT_TRUE ? 1 : 0;
return S_OK;
}