.dll Question Dynamically loading Module DLLs

meson800

Addon Developer
Addon Developer
Donator
Joined
Aug 6, 2011
Messages
405
Reaction score
2
Points
18
So I had an idea, and it involves dynamically loading module DLLs, much like Orbiter does.

So I began with testing with one of them, everyone's favorite, ScnEditor.dll

Using Dependency Walker, I found all the DLL exports, and dynamically loaded them, and tried to pass along the Orbiter callbacks.

Interestingly, nothing crashes (surprisingly, actually :lol:), until I tried to use the scenario editor.

With my DLL being the only module loaded (the actual ScnEditor is not loaded), two copies of Scenario Editor appear in the Custom menu. The first one crashes due to some memory access in my DLL, whereas the second one works.

Debugging my code, scInit is only called once, but two entries are still added.

Here's my code:
Code:
HMODULE scenarioEditorDLL;
typedef void(*ExternalInitModule)(HINSTANCE);
typedef void(*ExternalExitModule)(HINSTANCE);
typedef void(*ExternalPause)(bool);
typedef void(*ExternalDeleteVessel)(OBJHANDLE hVessel);
ExternalInitModule scInit;
ExternalExitModule scExit;
ExternalPause scPause;
ExternalDeleteVessel scDeleteVessel;

DLLCLBK void InitModule(HINSTANCE hDLL)
{

    scenarioEditorDLL = LoadLibrary("ORBITER_ROOT\\Modules\\Plugin\\ScnEditor.dll"); //replaced with actual path to orbiter root in my code
    scInit = (ExternalInitModule)GetProcAddress(scenarioEditorDLL, "InitModule");
    scExit = (ExternalExitModule)GetProcAddress(scenarioEditorDLL, "ExitModule");
    scPause = (ExternalPause)GetProcAddress(scenarioEditorDLL, "opcPause");
    scDeleteVessel = (ExternalDeleteVessel)GetProcAddress(scenarioEditorDLL, "opcDeleteVessel");

    scInit(scenarioEditorDLL);
}

DLLCLBK void opcPause(bool pause)
{
    scPause(pause);
}

DLLCLBK void ExitModule(HINSTANCE hDLL)
{
    scExit(scenarioEditorDLL);
}

DLLCLBK void opcDeleteVessel(OBJHANDLE hVessel)
{
    scDeleteVessel(hVessel);
}

The offending line is likely:
Code:
    scInit(scenarioEditorDLL);

All other "forwarded" functions work without crashing. I am forwarding all of ScnEditor's exports, except ModuleDate and GetModuleVersion.


At first, I tried using my DLLs handle as the argument to scInit:
Code:
scInit(hDLL)
But that fails because scenario editor then tries to load non-existent images from inside my DLL with ScnEditor's offset.


What would be the correct way to dynamically load and forward a DLL (if there is one)?
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,390
Reaction score
577
Points
153
Location
Vienna
AFAIK, "InitModule" could be called from DllMain, too. DllMain is called by LoadLibrary, so you probably ran the editor's init code twice, resulting in 2 entries, with only one working because the other one got its global fields overwritten.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,842
Reaction score
2,105
Points
203
Location
between the planets
So I had an idea, and it involves dynamically loading module DLLs, much like Orbiter does.

I see plans within plans... :shifty:

What have you thought up now? :lol:
 

meson800

Addon Developer
Addon Developer
Donator
Joined
Aug 6, 2011
Messages
405
Reaction score
2
Points
18
AFAIK, "InitModule" could be called from DllMain, too. DllMain is called by LoadLibrary, so you probably ran the editor's init code twice, resulting in 2 entries, with only one working because the other one got its global fields overwritten.

That sounds a lot like the problem I'm having :tiphat:

It would also make sense if there was a Orbiter-provided DLLMain, such as
Code:
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
        InitModule(hinstDLL);
    else if (fdwReason == DLL_PROCESS_DETACH)
        ExitModule(hinstDLL);
}

But I can't find anything like that :(

Looking in Orbitersdk/samples/ScnEditor, DLLMain is not defined in the code there.

Then I thought that maybe Orbitersdk.h included something like that, but the closest I could find to anything related to ORBITER_MODULE was:
Code:
#ifdef ORBITER_MODULE
void dummy();
void calldummy () { dummy(); }
DLLCLBK char *ModuleDate () { return __DATE__; }
#endif
Which clearly doesn't implement DLLMain. In fact, none of the header files in Orbitersdk/include reference DLLMain.

jedidia said:
I see plans within plans...

What have you thought up now?
:lol: This actually doesn't involve SE. I'm actually seeing if I can create a "wrapper" around other Orbiter DLLs, to provide additional information when a CTD happens to make figuring out what causes one easier.
 

orb

O-F Administrator,
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
But I can't find anything like that :(
DllMain isn't available in source/headers form. It's pre-compiled code contained in Orbitersdk.lib which is linked with the modules.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,390
Reaction score
577
Points
153
Location
Vienna

orb already explained the DllMain issue.

I'm actually seeing if I can create a "wrapper" around other Orbiter DLLs, to provide additional information when a CTD happens to make figuring out what causes one easier.

I did that for genericvessel in order to have a better versioning story. In essence it uses late-binding to load the right vessel DLL, then propagates Orbiter's calls to the loaded module. From my experience it is tricky, but quite doable.
 
Top