Reputation: 41
I've done this before, but with this specific button, it doesn't work!
If I click the button manually it creates a new window (mini-map): Image
/////// But Programmatically I can see the animation on the button as if it gets clicked gif,
But the window (mini-map) doesn't show up.
int x = 9, y = 8;
IntPtr lParam = (IntPtr)((y << 16) | x);
WinAPIs.PostMessage(button, WinAPIs.WM_LBUTTONDOWN, (IntPtr)0x01, lParam);
WinAPIs.PostMessage(button, WinAPIs.WM_LBUTTONUP, IntPtr.Zero, lParam);
The mini-map is created only if the mouse is over the button when my code sends the messages.
Here's a 10-sec video on YT: Video,
Notice: In the video, I didn't click the button with the mouse, I've just hovered it.
UPDATE1: Spy++ Messages Image
UPDATE2: the game is using GetCursorPos and WindowFromPoint to get the handle of the window under the cursor and compare it with the button's handle, I need to figure out how to hook WindowFromPoint to send the button's handle even if the game is in the background.
Upvotes: 0
Views: 2250
Reputation: 41
I've found the answer,
First of all, I had to reverse-engineer the game,
And I've found that it's using WindowFromPoint to get the handle of the window under the current cursor's position and compare it with the button's handle.
Meaning the bot will not work while the game is in the background.
So I had to figure out how to hook the WindowFromPoint call and change the return value, so I can send the button's handle even if the game is in the background.
I used this library to do so: Deviare.
And here is a Quickstart of how to use it.
Here is my code:
using System;
using System.Windows.Forms;
using Nektra.Deviare2;
public partial class Form1 : Form
{
private NktSpyMgr _spyMgr;
public Form1()
{
InitializeComponent();
_spyMgr = new NktSpyMgr();
_spyMgr.Initialize();
_spyMgr.OnFunctionCalled += new DNktSpyMgrEvents_OnFunctionCalledEventHandler(OnFunctionCalled);
}
private void Form1_Load(object sender, EventArgs e)
{
//Search for the game process
var processes = System.Diagnostics.Process.GetProcessesByName("Conquer");
int processID = 0;
if (processes.Length < 1)
{
MessageBox.Show("Couldn't find Conquer", "Error");
Environment.Exit(0);
}
else
{
//Found the game
processID = processes[0].Id;
}
//Hook WindowFromPoint with 'flgOnlyPostCall' meaning OnFunctionCalled will be triggered after the api call and before the value returns to the game
NktHook hook = _spyMgr.CreateHook("user32.dll!WindowFromPoint", (int)(eNktHookFlags.flgRestrictAutoHookToSameExecutable | eNktHookFlags.flgOnlyPostCall));
hook.Hook(true);
hook.Attach(processID, true);
//Now send the button click and It works.
int x = 9, y = 8;
IntPtr lParam = (IntPtr)((y << 16) | x);
WinAPIs.PostMessage((IntPtr)0x1D02D0, WinAPIs.WM_LBUTTONDOWN, (IntPtr)0x01, lParam);
WinAPIs.PostMessage((IntPtr)0x1D02D0, WinAPIs.WM_LBUTTONUP, IntPtr.Zero, lParam);
}
private static void OnFunctionCalled(NktHook hook, NktProcess process, NktHookCallInfo hookCallInfo)
{
INktParam pRes = hookCallInfo.Result();
//change the return value to whatever you want.. 0x1D02D0 here for example
pRes.Value = new IntPtr(0x1D02D0);
}
}
Upvotes: 3