In the ConsoleModuleLoader, we have a function called GetArtPath that actually exists outside of the class.
int __fastcall GetArtPath(void*, int, char*, char*, char *destBuffer, int bufferSize, char *defaultValue)
{
strcpy_s(destBuffer, bufferSize, moduleDirectory.c_str());
return moduleDirectory.size();
}
Because GetArtPath exists outside the class, the variable moduleDirectory must also live outside the class. This means that moduleDirectory is shared between all instances of ConsoleModuleLoader and is not wiped when new versions of ConsoleModuleLoader are instantiated.
This is okay for the production use of op2ext since only one instance of ConsoleModuleLoader is needed.
Now that we have added unit tests to op2ext, the unit tests will create multiple instances of ConsoleModuleLoader to test different aspects of the code. Because moduleDirectory exists outside of the class ConsoleModuleLoader, it persists and is shared between all instances, which is not ideal.
To remedy the situation, I wanted to bring GetArtPath into the class. However, I cannot figure out how to accomplish it.
I attempted to translate GetArtPath from a calling convention of __fastcall to __thiscall. Since __fastcall passes the second argument in the EDX register, and __thiscall does not, I removed the first argument void* from the GetArtPath's signature. Don't know if this is legal, I'm out of my wheelhouse here...
I tried to remove __fastcall by rewritting the function signature as:
int ConsoleModuleLoader::GetArtPath(int, char*, char*, char *destBuffer, int bufferSize, char *defaultValue)
{
strcpy_s(destBuffer, bufferSize, moduleDirectory.c_str());
return moduleDirectory.size();
}
Notice that __fastcall is removed, the first argument void* is removed, and the function is now a member of ConsoleModuleLoader. I think maybe these changes keep the function signature in sync???
However, when compiling the function SetArtPath, throws 2 compile time errors
E0171 invalid type conversion op2extStatic \op2ext\srcStatic\ConsoleModuleLoader.cpp 114 These errors are caused by the phrase (DWORD)(&GetArtPath). I'm not sure why I cannot cast to a DWORD once the function is a member of the class. Full function definition below for context.
void ConsoleModuleLoader::SetArtPath()
{
// This value may also be set using the DEBUG section of the .ini file, using the property ART_PATH.
// If set in .ini file, ART_PATH must be deleted at end of session or will persist between plays.
// Insert hooks to make OP2 look for files in the module's directory
// In ResManager::GetFilePath
Op2MemSetDword((void*)0x004715C5, (DWORD)(&GetArtPath) - (GetLoadOffset() + (DWORD)0x004715C5 + sizeof(void*)));
// In ResManager::CreateStream
Op2MemSetDword((void*)0x00471B87, (DWORD)&GetArtPath - (GetLoadOffset() + (DWORD)0x00471B87 + sizeof(void*)));
}
I'm looking for an assist from someone with better assembly and C++ knowledge than myself.
-Brett