1

I have two methods, an int, grabDump, and a string, dumpCsToString, as part of one of my libraries, called OffsetGrabber. These 2 methods, when referenced in any way, return "unresolved external symbol". The other four methods I have in my library return no error.

Checking if the declaration and definition were equal (they were), checking if I wasn't including something (I had everything I needed to include), and checking if I referenced the header file of the library (which I did)

#pragma once

#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <stdint.h>
#include <string>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <TlHelp32.h>
#include <Lmcons.h>
#include <Commdlg.h>
#include <tchar.h>
#include <string>

//problematic
std::string dumpCsToString();
int grabDump(std::string MetadataFile, std::string toGrab, std::string valClass);
//not problematic
int grabOffsetFromCache(std::string cacheContent, std::string delimiter);
int saveOffsetToCache(std::string path, int patchOffset, std::string delimiter);
BOOL patchToMemory(BYTE* aob, int patchOffset, int aobSize);
BOOL readFromMemory(BYTE* aob, int patchOffset, int aobSize);

This is my header file for the library. The ones that return unresolved external symbol are labeled as "problematic", the ones that don't are labeled as "not problematic".

std::string dumpCsToString()
{
    wstring toConvert = openDumpCs();
    string converted = string(toConvert.begin(), toConvert.end());
    return converted;
}

This is one of the problematic methods, dumpCsToString. This simply converts a wstring, "openDumpCs", to a string. This is what openDumpCs looks like;

wstring openDumpCs(HWND owner = NULL)
{
    wchar_t buffer[MAX_PATH] = L"";

    OPENFILENAMEW ofn = { 0 };

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = owner;
    ofn.lpstrFilter = L"Dump.cs file\0*.*\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = buffer;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;

    if (!GetOpenFileNameW(&ofn))
        return L"";

    return buffer;
}

This opens up a file prompt to select a file named "dump.cs", and saves its path as a wstring. This is converted through the use of dumpCsToString().

int grabDump(std::string MetadataFile, std::string toGrab, std::string valClass)
{
    ifstream MetadataStream(MetadataFile);
    string compStr;
    string method;
    string methodClass;

    // look for specified string, return true if found and stop loop preemptively, grab the line
    while (getline(MetadataStream, compStr) && method == "")
    {
        if (compStr.find(valClass) != string::npos)
        {
            methodClass = compStr;
        }

        if (methodClass != "" && compStr.find(toGrab) != string::npos)
        {
            method = compStr;
        }
    }

    // split the line's string into just offset
    size_t pos = 0;
    string token;
    string delimiter = "Offset: 0x";
    while ((pos = method.find(delimiter)) != string::npos) {
        token = method.substr(0, pos);
        method.erase(0, pos + delimiter.length());
    }

    // create a string stream to convert this offset to a normal integer
    int offset;
    stringstream ss;
    ss << std::hex << method;
    ss >> offset;
    offset += 5120;

    return offset;
}

Finally, this is grabDump. The first parameter, MetadataFile, is whatever the result of dumpCsToString() is (we'll see this later). toGrab is the string we are looking for inside of the dump.cs file. valClass is the class toGrab is inside of. It makes a file stream from MetadataFile, and goes through it to look for valClass, then looks for toGrab afterwards. Once both are found, it proceeds to split the line's string into just a number (the line's string should resemble "public int xxxxxxx(); //Offset: 0xABCD9F"). It converts this number from hex to an integer, and adds 5120 to it.

Here's how I've called it in my application:

string dump = dumpCsToString();
patchOffset = grabDump(dump, "public float get_Rate();", "WeaponModel : Model");
deg2RadOffset = grabDump(dump, "public static float get_Deg2Rad();", "Math");
raceTimeOffset = grabDump(dump, "public float GetRaceTime();", "UnityToSimulation");

Note that patchOffset, deg2RadOffset, and raceTimeOffset were all declared previously.

I have no idea why I'm getting this error with these 2 particular methods as all culprits I've seen do not check out.

Expected result:

No errors, grabDump successfully returns a number.

Actual result:

dllmain.obj : error LNK2019: unresolved external symbol "class std::basic_string,class std::allocator > __cdecl dumpCsToString(void)" (?dumpCsToString@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function applyMod

dllmain.obj : error LNK2019: unresolved external symbol "int __cdecl grabDump(class std::basic_string,class std::allocator >,class std::basic_string,class std::allocator >,class std::basic_string,class std::allocator >)" (?grabDump@@YAHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@00@Z) referenced in function applyMod

C:\Users\kadin_000\source\repos\Ben3874\BTD6MAPI\x64\Debug\HypersonicMod.btd6mod : fatal error LNK1120: 2 unresolved externals

BowDown097
  • 11
  • 1

0 Answers0