0

I want to be able to instantiate and use the same object instance in several .h files so that: a) that object can be instantiated once and then re-used in several places b) the value for one of the variables of that object instance is to be updated later in the code and thus available to all of the functions which are set to use it

Example:

Let's say the object is called: AdressHelper and it is defined in AdressHelper.h. Like this:

class AddressHelper {
private:
    uint32_t pid;
    DWORD_PTR baseAddressPtr;
public:
    AddressHelper(uint32_t pid) {
        this->pid = pid;
        this->baseAddressPtr = this->GetProcessBaseAddress(pid);
    }
    DWORD_PTR GetProcessBaseAddress(DWORD processID)
    {
        DWORD_PTR   base_address = 0;
        //... initialize base_address with something
        return base_address;
    }
    DWORD_PTR GetBaseAddress() {
        if (this != NULL) {
            return this->baseAddressPtr;
        }
    }

    void SetBaseAddress() {
        if (this != NULL) {
            this->baseAddressPtr = GetProcessBaseAddress(pid);
        }
    }
};

Now, I have Globals.h which describes this object like this:

#pragma once
#include "AdressHelper.h"
#include <cstddef>

extern AddressHelper* addressHelper;

If I instantiate addressHelper in file gui.h

#pragma once
#include "world.h"
#include <array>
#include "Globals.h"

AddressHelper* addressHelper = new AddressHelper(GetCurrentProcessId());

I can then use addressHelper in gui.cpp

addressHelper->GetBaseAddress() + 0xb81074;

But how do I now refer to the same instance of addressHelper in world.h for example?

I can't do #include "Globals.h" for example in world.h as compiler starts to complain that addressHelper is already instantiated in gui.obj.

The reason is probably as world.h is already included to gui.h and there is cycle dependency. But I can't drop that link for now and still want to do what I have stated above. Any way to achieve this?

jxh
  • 69,070
  • 8
  • 110
  • 193
Irbis77
  • 163
  • 1
  • 8
  • 1
    If you really want to use globals (which I do not advise you to do), then just declare a struct and have a `static` member that is `public`. Then you have no issues with the linkage if you refer to that static member. You could include that `struct` in a header, and the linker will not complain if it sees the `struct` more than once (as long as you define the member in one CPP source file somewhere). It also gets rid of the `extern` stuff you're doing now. – PaulMcKenzie Oct 04 '21 at 17:22
  • 1
    Use something like the Singleton (anti?) pattern. – jxh Oct 04 '21 at 17:28
  • https://stackoverflow.com/q/1008019/315052 – jxh Oct 04 '21 at 17:31
  • Per the accepted answer in the linked question, add a static `getInstance` method to your `AddressHelper` class. Then, users can access it with `AddressHelper::getInstance()->GetBaseAddress()`, for example. – jxh Oct 04 '21 at 17:33
  • 1
    IMO when I see a program with `extern`, it comes from someone with a `C` background who doesn't know about the alternatives in C++, or a current/former C programmer who wants to jump to something they are familiar with without thought. Unfortunately, some well-known C++ frameworks from way back used `extern` variables, so I can't really just blame the run-of-the-mill C++ programmer alone. – PaulMcKenzie Oct 04 '21 at 17:36
  • 1
    The code you have that tests `if (this != NULL)` is pointless and should be removed. – jarmod Oct 04 '21 at 17:48
  • 1
    Yes, the `this != NULL` test should be removed. The compiler will see that, and may throw out that entire block of code, regardless of whether `this` is NULL or not. The reason is that it will see you are doing a nonsense `if` statement, thus anything to do with that statement could be removed by the optimizer. – PaulMcKenzie Oct 04 '21 at 18:02
  • *"Let's say the object is called:* AdressHelper *and it is defined in **AdressHelper.h**.*" -- It's a class, not an object, that is called `AddressHelper` (with a capital "A") and that is defined in that header. – JaMiT Oct 05 '21 at 00:41
  • *"If I instantiate addressHelper in file **gui.h**"* -- why would you instantiate in a header file? That's a good way to end up violating the One Definition Rule and getting the linker to complain that `addressHelper` exists in multiple object files. – JaMiT Oct 05 '21 at 00:46
  • AddressHelper::getInstance()->GetBaseAddress() solution works in a way that now the same instance is used across the program. But the second part of the requirement is still not satisfied. I.e. when AddressHelper::getInstance()->SetBaseAddress(), baseAddress is updated, but for all appearances of AddressHelper::getInstance()->GetBaseAddress() called before that the baseAddress value stays as it was before Setter call. I need it to be updated those previous calls of Getter as well... – Irbis77 Oct 05 '21 at 06:21
  • @jamod Had if (this!=0) removed. It was legacy of the previous call as originally object was instantiated with the NULL value. – Irbis77 Oct 05 '21 at 06:26
  • @JaMiT because I was trying to satisfy the original requirement, I.e. having the same instance available across several .h files. Which didn't work. But you are right, it created an issue with multiple intantiations. – Irbis77 Oct 05 '21 at 07:22

1 Answers1

0

Solved in the following way:

class AddressHelper {
private:
    uint32_t pid;
    DWORD_PTR baseAddressPtr;


public:
    AddressHelper() {
    }

    static AddressHelper& getInstance()
    {
        static AddressHelper instance; // Guaranteed to be destroyed.
                                       // Instantiated on first use.
        return instance;
    }

    DWORD_PTR GetProcessBaseAddress(DWORD processID)
    {
        DWORD_PTR   base_address = 0;
        HANDLE      processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
        HMODULE* moduleArray;
        LPBYTE      moduleArrayBytes;
        DWORD       bytesRequired;

        if (processHandle)
        {

            if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
            {
                if (bytesRequired)
                {
                    moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);

                    if (moduleArrayBytes)
                    {
                        unsigned int moduleCount;

                        moduleCount = bytesRequired / sizeof(HMODULE);
                        moduleArray = (HMODULE*)moduleArrayBytes;

                        if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
                        {
                            base_address = (DWORD_PTR)moduleArray[0];
                        }

                        LocalFree(moduleArrayBytes);
                    }
                }
            }
            // base_address = (DWORD_PTR)GetModuleHandle(NULL);
            CloseHandle(processHandle);
        }

        return base_address;
    }
    DWORD_PTR& GetBaseAddress() {
            return baseAddressPtr;
    }

    void SetBaseAddress(uint32_t pid = GetCurrentProcessId()) {
            baseAddressPtr = GetProcessBaseAddress(pid);
    }

};

and now everywhere the &AddressHelper::getInstance().GetBaseAddress() is called

which can be (re)set with AddressHelper::getInstance().SetBaseAddress();

Irbis77
  • 163
  • 1
  • 8