-3

So basically I got a Window Handler which is a Pic(rectangular shape) that contains like 16 slots.

Well, so I want to use SendMessage to this hWnd and giving a keyPressed as a message to the first and to the second slot (since they are not individual windows, I can't take each slot window Handle). The problem resides in implementing those offsets to set the area which I want to send those messages.

Basically I am making a trainer for an offline game to practice things with memory management and to learn how WINAPI works. Here is the code (not including the DllMain function).

#include <windows.h>
#include <stdio.h>

#define VIDAACTUAL 0x70D27E
#define VIDAMAX 0x70D27C
#define MANAACTUAL 0x70D282
#define MANAMAX 0x70D280

void AutoPot(){
    Sleep(5000); //Giving myself time to place the cursor.
    POINT P;
    GetCursorPos(&P);
    HWND hwnd = WindowFromPoint(P);
    Sleep(50);
    while (1){
        WORD hpMax = *(WORD*)(VIDAMAX);
        WORD hpAct= *(WORD*)(VIDAACTUAL);
        WORD mpMax = *(WORD*)(MANAMAX);
        WORD mpAct = *(WORD*)(MANAACTUAL);
        if (hpAct != 0)
        {
            if (hpAct != hpMax)
            {
                SendMessage(hwnd, WM_LBUTTONUP, 0, 0);
                //SendMessage(hwnd, WM_LBUTTONDBLCLK, 0, 0);
                //SendMessage(hwnd, VK_SPACE, 0, 0);
            }
            else if (mpAct!= mpMax && mpMax != 0){ //Giving priority to red pots.
                SendMessage(hwnd, WM_LBUTTONUP, 0,0);
                //SendMessage(hwnd, WM_LBUTTONDBLCLK, 0,0);
                //SendMessage(hwnd, VK_SPACE, 0, 0);
            }
        }
        Sleep(50);
    }
}

So, is there a way to select a specific area inside a hWnd to send those messages?

xBurnsed
  • 410
  • 4
  • 12

2 Answers2

0

You are not specifying the correct mouse coordinates when sending the messages. GetCursorPos() returns the current mouse position in screen coordinates, which you then need to convert into client coordinates when sending mouse messages to the window, eg:

#include <windows.h>
#include <stdio.h>

#define VIDAACTUAL 0x70D27E
#define VIDAMAX 0x70D27C
#define MANAACTUAL 0x70D282
#define MANAMAX 0x70D280

void AutoPot()
{
    Sleep(5000); //Giving myself time to place the cursor.
    POINT P;
    GetCursorPos(&P);
    HWND hwnd = WindowFromPoint(P);
    ScreenToClient(hwnd, &P); // <-- here
    Sleep(50);
    while (1){
        WORD hpMax = *(WORD*)(VIDAMAX);
        WORD hpAct= *(WORD*)(VIDAACTUAL);
        WORD mpMax = *(WORD*)(MANAMAX);
        WORD mpAct = *(WORD*)(MANAACTUAL);
        if (hpAct != 0)
        {
            if (hpAct != hpMax)
            {
                PostMessage(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(P.x, P.y));
                //PostMessage(hwnd, WM_LBUTTONDBLCLK, 0, MAKELPARAM(P.x, P.y));
            }
            else if ((mpAct != mpMax) && (mpMax != 0)) //Giving priority to red pots.
            {
                PostMessage(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(P.x, P.y));
                //PostMessage(hwnd, WM_LBUTTONDBLCLK, 0, MAKELPARAM(P.x, P.y));
            }
        }
        Sleep(50);
    }
}

And FYI, VK_SPACE is not a valid message identifier (its value is 0x20, which is the same value as the WM_SETCURSOR message). You would have to use WM_KEYDOWN and WM_KEYUP instead, and/or WM_CHAR directly. However, you can’t simulate keyboard input with PostMessage.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Wow. That was a good answer. Thank you sir! I used SendMessage tho, I don't know the real difference, but I can still use my other Keys with send message :) – xBurnsed Feb 24 '16 at 15:32
  • By the way, what does MAKELPARAM stand for? – xBurnsed Feb 24 '16 at 15:33
  • @Burnsedd: `PostMessage()` posts the message into the window's message queue and then returns immediately, not waiting for the message to be processed. `SendMessage()` sends the message directly to the window's message procedure and does not return until the message is processed. See [Using Messages and Message Queues](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928.aspx). As for [`MAKELPARAM()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632661.aspx), it "*creates a value for use as an `lParam` parameter in a message*". – Remy Lebeau Feb 24 '16 at 16:02
  • Yeah but what is lParam used for in this context? – xBurnsed Feb 24 '16 at 18:09
  • If you read the documentation for [`WM_LBUTTONUP`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645608.aspx) and [`WM_LBUTTONDBLCLK`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645606.aspx), it tells you *exactly* what the `lParam` is used for: "*lParam: **The low-order word specifies the x-coordinate of the cursor**. The coordinate is relative to the upper-left corner of the client area. **The high-order word specifies the y-coordinate of the cursor**. The coordinate is relative to the upper-left corner of the client area.*" – Remy Lebeau Feb 24 '16 at 18:12
  • Thanks Remy. In your OP you said this: "However, you can’t simulate keyboard input with PostMessage." What about simulating keyboard inputs with SendMessage? – xBurnsed Feb 24 '16 at 18:20
  • @Burnsedd: Same problem, but even worse since it bypasses the message queue altogether. Normal user input goes through the queue, and various state machine logics depend on it to maintain accurate information. – Remy Lebeau Feb 24 '16 at 18:24
-2

Windows send mouse messages to a window based on the upper left hand corner. So top left of your window is (0,0). If you know the location of the item you wish to send a message to then pass them in your sendmessage. If not you'll have to call getClientRect(hWnd...) and do some math :)

//we get the client rect
RECT rect;
GetClientRect(hWnd, &rect);

//rect = { LONG top, left, right bottom }
//i guess here we divide the rect into 4x4 squares (no idea of your layout)
//so pick a square to get xpos and ypos
int x, y; //can't calculate these i have no idea of your layout

LPARAM lParam = MAKELPARAM(x, y);
PostMessage(hWnd, WM_LBUTTONDOWN, 0, lParam); //NOT SendMessage!!!

One fly in the ointment may be that windows interprets WM_LBUTTON message coordinates as screen coords. In that case we have to work backwards. Having figured out where we want to click in the client area we need to know the screen coordinates for that. In that case we use (a kind user has pointed out that it doesn't translate the coordinates so ignore this bit - just send the client coords)

POINT thePointWeWantOnTheClient;
ClientToScreen(hWnd, &thePointWeWantOnTheClient);

And use this point instead. I have no way of testing this until tomorrow morning.

Worth pointing out that SendMessage is blocking so it will block the GUI. PostMessage just stuffs in the message queue which is what you want.

systemcpro
  • 856
  • 1
  • 7
  • 15
  • Well it happens that (0,0) it is the middle left, not the left top corner. Could you give me an example on how to use getClientRect in that situation? And even if I manage to get those coords, how do I apply them with SendMessage? – xBurnsed Feb 23 '16 at 22:49
  • @systemcpro: "*windows interprets WM_LBUTTON message coordinates as screen coords*" - no, it doesn't. Read the [documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645607.aspx). The coordinates are client coordinates relative to the receiving window's client area, they are not screen coordinates. – Remy Lebeau Feb 24 '16 at 00:28
  • That's why it was an addendum and I used the word MAY I couldn't quite remember. Besides there's no harm in knowing it and now you have clarified both myself and most of the world are wiser – systemcpro Feb 24 '16 at 00:32