Search code examples
c++windowsvisual-c++win32gui

A non static member reference must be relative to a specific object c++


I'm trying to test a boolean condition but for some reason, it won't even let me call the function in my window class. I have tried creating an object and inheriting the functions and still getting the same message. it will let me do if(Attach::attachProc) This always returns true when it's meant to return false in the demo. but not if(AttachProc()). the source for the window class Windows.cpp

#include "Window.h"
#include "Attach.h"
Window* window = nullptr;
Attach attach;
Window::Window()
{
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    
    switch (msg)
    {
    case WM_CREATE:
    {
        
        //Event fired when the windows will be created
        break;
    }
    case WM_COMMAND:
        switch (LOWORD(wparam))
        {
        case ID_INJECT:
            if (Attach::attachProc())
            {
                MessageBox(0, "injected", "", MB_ICONERROR | MB_OK);
            }
            else
            {
                MessageBox(0, "faile to inject", "", MB_ICONERROR | MB_OK);
            }
        default:
            break;
        }
    case WM_DESTROY:
    {
        window->onDestroy();
        //Event fired when the window will be destroyed
        ::PostQuitMessage(0);
        break;

    }

    default:
        return ::DefWindowProc(hwnd, msg, wparam, lparam);

    }
    return NULL;
}
bool Window::init()
{
    WNDCLASSEX wc;
    wc.cbClsExtra = NULL;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.cbWndExtra = NULL;
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wc.hInstance = NULL;
    wc.lpszClassName = "MyWindowClass";
    wc.lpszMenuName = "";
    wc.style = NULL;
    wc.lpfnWndProc = WndProc;

    if (!::RegisterClassEx(&wc))
        return false;

    if (!window)
        window = this;

   m_hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "T3chSpl10ts", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT
        , CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
   //if creation fails return false
   if (!m_hwnd)
       return false;
   b_hwnd = CreateWindow("Button", "Inject",
       WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 20, 100, 30,
       m_hwnd, (HMENU)ID_INJECT, GetModuleHandle(NULL), NULL);

   //show up the window
   ::ShowWindow(m_hwnd, SW_SHOW);
   ::UpdateWindow(m_hwnd);


   //set this flag to indicate that the window is initialized and running
   m_is_run = true;
      return true;
}

bool Window::broadcast()
{
    MSG msg;
    while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    Sleep(0);

    return true;
}

bool Window::release()
{
    //Destroy the window
    if (!::DestroyWindow(m_hwnd))
        return false;
    return true;
}

bool Window::isRun()
{
    return m_is_run;
}

void Window::onDestroy()
{
    m_is_run = false;
}

Window::~Window()
{
}

Window.h

    #pragma once
#include <Windows.h>
#include "Attach.h"
#define Button 0
#define ID_INJECT 1
class Window : public Attach
{
public:
    Window();
    ~Window();
    bool init();//Initializes the window
    bool broadcast();

    bool isRun();
    bool release();
    virtual void onDestroy();
    //virtual void onCreate();
    //virtual void onUpdate();
    
protected:
    HWND m_hwnd;
    HWND b_hwnd;
    bool m_is_run;
    
};

attach.h

    #pragma once
#include<Windows.h>
#include<TlHelp32.h>
#include<cstdlib>
#include<iostream>

class Attach
{
public:
    bool attachProc();
    
protected:
    char procName[12]{ "Hi" };
    HANDLE hProc = NULL;
    DWORD pID;
};
template <class datatype>
void wpm(datatype valToWrite, DWORD addressToWrite);
template <class datatype>
datatype rpm(DWORD addressToRead);

Solution

  • You are trying to use methods inside the window procedure. The problem is that the window procedure is a free function, meaning that it has no this object, but only a HWND handle. You must first identify the Window object for which the window procedure is called.

    A common way is to use SetWindowLongPtr to store a pointer to the C++ object in the extra window memory. Then you can safely extract and use it in the WndProc function.

    How to:

    1. first reserve some extra memory for the window:

       wc.cbWndExtra = sizeof(LONG_PTR);
      
    2. pass a pointer to the object in the lpParam parameter of CreateWindow or CreateWindowEx

      m_hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MyWindowClass", "T3chSpl10ts",
           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT
           , CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, this);
      //if creation fails return false
      if (!m_hwnd)
          return false;
      
    3. store the pointer in that extra memory when processing the WM_CREATE or WM_NCCREATE message to later use it in WndProc:

       LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
       {
           Window *window = (Window *) GetWindowLongPtr(hwnd, 0);
           CREATESTRUCT* cs;
           ...
           case WM_CREATE:
               cs = (CREATESTRUCT*)lParam;
               ::SetWindowLongPtr(hwnd, 0, (LONG_PTR) cs->lpCreateParams);
               break;
           case WM_COMMAND:
               switch (LOWORD(wparam))
               {
               case ID_INJECT:
                   if (window->attachProc())
                   ...
      

    WM_NCCREATE and WM_CREATE are the first messages sent to the window. Initializing the pointer to the object at that moment allows to use it in other messages like WM_SIZE...