SDK Question Vessel DLL loading twice

meson800

Addon Developer
Addon Developer
Donator
Joined
Aug 6, 2011
Messages
405
Reaction score
3
Points
18
In the API guide, it states that:
When the user launches the simulation by picking a scenario from the Orbiter Launchpad dialog and pressing the “Launch Orbiter” button, Orbiter will load the vessel DLL module for each spacecraft type used in the simulation, and call its InitModule function. This function is called only once per Orbiter session, no matter how many spacecraft of that type appear in the simulation

In my work on catch-ctd, I hooked LoadLibraryA. It seems that DeltaGlider.dll is being loaded with LoadLibraryA twice!
Code:
--snipped init code and loading planet modules--
LoadLibraryA:(libFileName:Modules\ShuttlePB.dll)...
LoadLibraryA:(libFileName:[B]Modules\DeltaGlider.dll[/B])...
	oapiGetColour:(red:80 , green:80 , blue:224)...
	oapiGetColour:(red:160 , green:120 , blue:64)...
	oapiReadItem_bool:(f:00AEF3D0 , item:SCRAMJET , b:0)...
	oapiRegisterExhaustTexture:(name:Contrail1a)...
	oapiLoadMeshGlobal:(fname:DG\deltaglider_ns)...
	oapiLoadMeshGlobal:(fname:DG\DeltaGliderCockpit)...
	oapiCreateTextureSurface:(width:256 , height:256)...
	oapiGetTextureHandle:(hMesh:0889BBC0 , texidx:5)...
LoadLibraryA:(libFileName:.\LuaInline.dll)	
--snip--
LoadLibraryA:(libFileName:Modules\ShuttleA.dll)...
--snip--
LoadLibraryA:(libFileName:[B]Modules\DeltaGlider.dll[/B])...
	oapiGetColour:(red:80 , green:80 , blue:224)...
	oapiGetColour:(red:160 , green:120 , blue:64)...
	oapiReadItem_bool:(f:00AEF3D0 , item:SCRAMJET , b:0)...
	oapiRegisterExhaustTexture:(name:Contrail1a)...
	oapiLoadMeshGlobal:(fname:DG\deltaglider_ns)...
	oapiLoadMeshGlobal:(fname:DG\DeltaGliderCockpit)...
	oapiCreateTextureSurface:(width:256 , height:256)...
	oapiGetTextureHandle:(hMesh:0889BBC0 , texidx:5)...
	oapiAsyncScriptCmd:(hInterp:08A29920 , cmd:run('dg/aap'))...
	oapiReadScenario_nextline:(scn:00AEF59C , line:—Ðz·µÎ)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:STATUS Landed Mars)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:BASE Olympus)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:POS -135.4300001 12.7366196)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:HEADING 0.00)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:AFCMODE 7)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:PRPLEVEL 0:1.000000)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:NAVFREQ 0)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:XPDR 0)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:GEAR 1 1.0000)...
	oapiReadScenario_nextline:(scn:00AEF59C , line:AAP 0:0 0:0 0:0)...
--snip--

This was done with my standard test scenario, the DeltaGlider/Brighton Beach scenario.

Looking at the Orbiter API calls made, the first load of the DG DLL does some init code with colors and such, then moves on to loading Lua and some other functions.

Then, the last library to load is the DG DLL again, where it does the same 8 init calls. The rest of the log is normal simulation stuff, no more libraries are loading.

What's happening with this dual-loaded DLL?
 
Perhaps it is due to Startup modules and/or ScnEditor references?
 
Perhaps it is due to Startup modules and/or ScnEditor references?
Unfortunately, catch-ctd is the only module enabled; it's a clean install of Orbiter.

Also, the loading occurs after the scenario has started to load.

It's kind of looking like the DLL gets loaded for every vessel. With this scenario vessels:
Code:
BEGIN_SHIPS
ISS:ProjectAlpha_ISS
  STATUS Orbiting Earth
  ELEMENTS 6734918.8 0.00090 74.51300 169.03400 328.27760 375.78523 51981.60000000
  AROT 30.00 0.00 50.00
END
Mir
  STATUS Orbiting Earth
  ELEMENTS 6671000.2 0.00060 3.50000 360.00000 0.04937 200.87669 51981.60000000
  AROT 0.00 -45.00 90.00
END
Luna-OB1:Wheel
  STATUS Orbiting Moon
  ELEMENTS 2237981.0 0.00000 89.99959 0.00007 0.00007 258.06828 51981.60000000
  AROT 0.00 0.00 30.25
  VROT 0 0 10
END
GL-01:DeltaGlider
  STATUS Landed Earth
  BASE Cape Canaveral:1
  HEADING 150.00
  PRPLEVEL 0:1.000 1:1.000
  NAVFREQ 402 94 0 0
  XPDR 0
  NOSECONE 0 0.0000
  GEAR 1 1.0000
  AIRLOCK 0 0.0000
END
GL-02:DeltaGlider
  STATUS Landed Earth
  BASE Cape Canaveral:2
  HEADING 150.00
  PRPLEVEL 0:1.000 1:1.000
  NAVFREQ 402 94 0 0
  XPDR 0
  NOSECONE 0 0.0000
  GEAR 1 1.0000
  AIRLOCK 0 0.0000
END
GL-03:DeltaGlider
  STATUS Landed Earth
  BASE Cape Canaveral:3
  HEADING 150.00
  PRPLEVEL 0:1.000 1:1.000
  NAVFREQ 402 94 0 0
  XPDR 0
  NOSECONE 0 0.0000
  GEAR 1 1.0000
  AIRLOCK 0 0.0000
END
SH-02:ShuttleA
  STATUS Landed Earth
  BASE Cape Canaveral:5
  HEADING 100.00
  PRPLEVEL 0:1.000 1:1.000
  NAVFREQ 0 0
  XPDR 0
  PODANGLE 0.0000 0.0000
  DOCKSTATE 0 0.0000
  AIRLOCK 0 0.0000
END
SH-03:ShuttleA
  STATUS Landed Earth
  BASE Cape Canaveral:6
  HEADING 100.00
  PRPLEVEL 0:1.000 1:1.000
  NAVFREQ 0 0
  XPDR 0
  PODANGLE 0.0000 0.0000
  DOCKSTATE 0 0.0000
  AIRLOCK 0 0.0000
END
I get three calls to LoadLibrary for Deltaglider.dll, and two calls for ShuttleA.dll.

Furthermore, if I do enable ScenarioEditor, and create a DG later, I get this in the log:
Code:
oapiCreateVesselEx:(name:test , classname:Deltaglider , status:00AEF7F4)
LoadLibraryA:(libFileName:Modules\DeltaGlider.dll)...
		oapiGetColour:(red:80 , green:80 , blue:224)...
		oapiGetColour:(red:160 , green:120 , blue:64)...
		oapiReadItem_bool:(f:00AEF608 , item:SCRAMJET , b:0)...
		oapiRegisterExhaustTexture:(name:Contrail1a)...
		oapiLoadMeshGlobal:(fname:DG\deltaglider_ns)...
		oapiLoadMeshGlobal:(fname:DG\DeltaGliderCockpit)...
--init code all over again--

This seems to be in violation of the API guide.

My question is, can I use this? Is this standard behavior?

For catch-ctd, I'm planning on hooking ovcInit on every vessel DLL, to actually create a "proxy" vessel class that passes calls to the real vessel.

If the guide is correct, and InitModule/LoadLibrary is only called once per vessel, I'd have to create a bunch of detour functions for ovcInit (because I don't know which hooked ovcInit is trampolining my detour function)

But if Orbiter is supposed to call LoadLibrary before creating each vessel, as it seems to be, I can just hook LoadLibrary to unhook the last-called ovcInit and hook the newest DLL, knowing that that DLL's ovcInit will shortly be called.

---------- Post added at 11:07 AM ---------- Previous post was at 11:04 AM ----------

Found the answer.

From the docs on LoadLibrary
If the specified module is a DLL that is not already loaded for the calling process, the system calls the DLL's DllMain function with the DLL_PROCESS_ATTACH value. If DllMain returns TRUE, LoadLibrary returns a handle to the module.

So Orbiter "lazily" just calls LoadLibrary before creating each vessel. However, if the vessel has been loaded before, it appears LoadLibrary just passes the handle without re-calling DllMain.

Luckily for me, that means hooking is a lot easier, as the preceding call to LoadLibrary signals which vessel DLL I need to hook.
 
Back
Top