1

Im trying to load a dll I wrote in c++ to do some memory accessing for me into a python program Im writing. below are the header file and the cpp file of the dll:

//MemoryReader.h
#pragma once

#ifdef MEMORYREADER_EXPORTS
#define MEMORYREADER_API __declspec(dllexport)
#else
#define MEMORYREADER_API __declspec(dllimport)
#endif
#include <Windows.h>
#include <vector>

extern "C" MEMORYREADER_API DWORD GetModuleBaseAddress(TCHAR * lpszModuleName, DWORD pID);

extern "C" MEMORYREADER_API int GetAddressRaw(DWORD baseAdd, DWORD* offsetsBase, int size);

extern "C" MEMORYREADER_API int GetAddress(DWORD baseAdd, std::vector<DWORD> offsets);
//MemoryReader.cpp
#include <Windows.h>
#include "pch.h"
#include<TlHelp32.h>
#include <iostream>
#include <tchar.h> // _tcscmp
#include <vector>
DWORD GetModuleBaseAddress(TCHAR* lpszModuleName, DWORD pID)
{
    DWORD dwModuleBaseAddress = 0;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pID); // make snapshot of all modules within process
    MODULEENTRY32 ModuleEntry32 = { 0 };
    ModuleEntry32.dwSize = sizeof(MODULEENTRY32);

    if (Module32First(hSnapshot, &ModuleEntry32)) //store first Module in ModuleEntry32
    {
        do {
            if (_tcscmp(ModuleEntry32.szModule, lpszModuleName) == 0) // if Found Module matches Module we look for -> done!
            {
                dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
                break;
            }
        } while (Module32Next(hSnapshot, &ModuleEntry32)); // go through Module entries in Snapshot and store in ModuleEntry32


    }
    CloseHandle(hSnapshot);
    return dwModuleBaseAddress;
}


int GetAddress(DWORD baseAdd, std::vector<DWORD> offsets)
{
    DWORD offsetGameToBaseAdress = baseAdd;
    std::vector<DWORD> pointsOffsets = offsets;


    HWND hGameWindow = FindWindow(NULL, "Trackmania");
    if (hGameWindow == NULL) {
        std::cout << "Start the game!" << std::endl;
        return 0;
    }
    DWORD pID = NULL; // ID of our Game
    GetWindowThreadProcessId(hGameWindow, &pID);
    HANDLE processHandle = NULL;
    processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    if (processHandle == INVALID_HANDLE_VALUE || processHandle == NULL) { // error handling
        std::cout << "Failed to open process" << std::endl;
        return 0;
    }

    char gameName[] = "Trackmania.exe";
    DWORD gameBaseAddress = GetModuleBaseAddress(_T(gameName), pID);


    DWORD baseAddress = NULL;
    //Get value at gamebase+offset -> store it in baseAddress
    ReadProcessMemory(processHandle, (LPVOID)(gameBaseAddress + offsetGameToBaseAdress), &baseAddress, sizeof(baseAddress), NULL);
    std::cout << "debugginfo: baseaddress = " << std::hex << baseAddress << std::endl;
    DWORD targetAddress = baseAddress; //the Adress we need -> change now while going through offsets
    for (int i = 0; i < pointsOffsets.size() - 1; i++) // -1 because we dont want the value at the last offset
    {
        ReadProcessMemory(processHandle, (LPVOID)(targetAddress + pointsOffsets.at(i)), &targetAddress, sizeof(targetAddress), NULL);
        std::cout << "debugginfo: Value at offset = " << std::hex << targetAddress << std::endl;
    }
    targetAddress += pointsOffsets.at(pointsOffsets.size() - 1); //Add Last offset -> done!!
    return targetAddress;
}


int GetAddressRaw(DWORD baseAdd, DWORD* offsetsBase, int size)
{
    std::vector<DWORD> offsets(offsetsBase, offsetsBase + size);
    DWORD targetAddress = GetAddress(baseAdd, offsets);
    return targetAddress;
}

This all compiles fine and I built the dll and saved it into the project folder. This is the python code using ctypes to load the dll:

import ctypes
from ctypes import wintypes
from ctypes import cdll

readerDll = cdll.LoadLibrary('C:/Users/owenc/Documents/GitHub/TrackManiaRL/TrackmaniaActorCritic/MemoryReader/MemoryReader.dll')

def process_addresses(base_address, offsets):
    p1 = ctypes.wintypes.DWORD(int(base_address, 16))
    p2 = ctypes.c_char_p(offsets.encode('utf-8'))
    p3 = ctypes.c_int(len(offsets))
    address = readerDll.GetAddressRaw(p1, p2, p3)
    input(address)
    return address

the problem is that this code is throwing this error:

Traceback (most recent call last):
  File "C:/Users/owenc/Documents/GitHub/TrackManiaRL/TrackmaniaActorCritic/main.py", line 29, in <module>
    env = TrackmaniaEnv(speed_address, checkpoint_address, goal_address, VAEncoder)
  File "C:\Users\owenc\Documents\GitHub\TrackManiaRL\TrackmaniaActorCritic\environment.py", line 58, in __init__
    self.speed_address = process_addresses(spd_address, self.speed_offset)
  File "C:\Users\owenc\Documents\GitHub\TrackManiaRL\TrackmaniaActorCritic\environment.py", line 45, in process_addresses
    address = readerDll.GetAddressRaw(p1, p2, p3)
  File "C:\Users\owenc\anaconda3\envs\tf-gpu\lib\ctypes\__init__.py", line 377, in __getattr__
    func = self.__getitem__(name)
  File "C:\Users\owenc\anaconda3\envs\tf-gpu\lib\ctypes\__init__.py", line 382, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'GetAddressRaw' not found

Ive tried looking into the problem, but it seems like most people that get this error have simply accidentally left out the exern "C" or the __declspec(dllexport) in their c++ code. Ive tried a few variations on the python code, but I cant seem to find out why the function isnt being found.

Hopefully theres someone who knows ctypes well who can give me a hand here.

Owen Craig
  • 11
  • 1
  • You didn’t define MEMORYREADER_EXPORTS anywhere, did you? Thus dllexport isn’t used and the symbols aren’t seen – ead Jul 06 '21 at 16:55
  • Step from duplicate you are probably missing “ In your library build project create a define LIBRARY_EXPORTS this will cause your functions to be exported for your DLL build.” – ead Jul 06 '21 at 17:31
  • Ah yes in the code I posted I think I never defined MEMORYREADER_EXPORTS, however Ive tested it with that code commented out and MEMORYREADER_API deifned as __declspec(dllexport), but when I check the exports using DUMPBIN it doesnt list any exported functions – Owen Craig Jul 06 '21 at 20:52
  • You need to use MEMORYREADER_API when you define the functions in cpp, see duplicate how it is done. Include MemoryReader.h in cpp, then compiler will check that you define what you declare. – ead Jul 07 '21 at 03:29

0 Answers0