API Question Getting airfoil handles?

RisingFury

OBSP developer
Addon Developer
Joined
Aug 15, 2008
Messages
6,427
Reaction score
492
Points
173
Location
Among bits and Bytes...
I'm trying to predict the amount of lift a vessel creates at arbitrary (not only current) AOA, mach number,...

I found a function called GetAirfoilParam which asks for an airfoil handle and returns all of the airfoil's characteristics , including (amazingly enough) the pointer to the function that calculates the airfoil coefficients - AirfoilCoeffFunc and the parameters that need to be passed to it. Great, my dreams have all come true...

Now, how do I get all of the vessel's airfoil handles that the function requires to return the data?

I've looked through the API reference, searched the forum and even looked through the list of functions of the VESSEL class, but found nothing... I hope it's possible to get the handles. If not, then that seems like quite an oversight in the API and will hopefully be corrected in the future Orbiter release... and in the mean time, I'll have to resort to logging...

---------- Post added 29th Oct 2012 at 02:30 ---------- Previous post was 28th Oct 2012 at 20:56 ----------

In the mean time, I'd like to say that this sledgehammer works... ish

Code:
for (unsigned int I = 0; I < (unsigned int) pow(2.0, 32) - 1; I++)
	{
		if (Parent->GetAirfoilParam(AIRFOILHANDLE(I), &ReferenceVector, &Function, &Context, &C, &S, &A) == true)
		{
			AirfoilHandles.push_back(AIRFOILHANDLE(I));
		}
	}

Basically a for loop through the entire memory, looking for where the function returns true, however, on my computer it takes 15 seconds for every vessel in the scenario. It's unacceptable.

Alternatives?
 
Last edited:

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Alternatives?
You can for example hook these Orbiter.exe exported functions (replace addresses of them in the export table of the loaded orbiter.exe image with addresses of your replacement functions, after saving them first, for calling them from your functions and for unhooking in ExitModule) in InitModule of your plug-in:
Code:
?CreateAirfoil@VESSEL@@QBEXW4AIRFOIL_ORIENTATION@@ABTVECTOR3@@P6AXNNNPAN22@ZNNN@Z
?CreateAirfoil2@VESSEL@@QBEPAXW4AIRFOIL_ORIENTATION@@ABTVECTOR3@@P6AXNNNPAN22@ZNNN@Z
?CreateAirfoil3@VESSEL@@QBEPAXW4AIRFOIL_ORIENTATION@@ABTVECTOR3@@P6AXPAV1@NNNPAXPAN44@Z3NNN@Z
The code of the replacement functions would simply call their original versions, but also would add the returned AIRFOILHANDLE to your array/vector, before they actually return it to the caller.

(Note: ECX register contains the vessel class instance address on entry to these functions.)
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
I was asked in a PM how to do it. Here's a plug-in module that hooks CreateAirfoil2 and CreateAirfoil3:
Code:
#define STRICT
#define ORBITER_MODULE
#include "windows.h"
#include "orbitersdk.h"
#include <vector>

// ==============================================================
// Common literals

#define MANGLED_CREATE_AIRFOIL2 "?CreateAirfoil2@VESSEL@@QBEPAXW4AIRFOIL_ORIENTATION@@ABTVECTOR3@@P6AXNNNPAN22@ZNNN@Z"
#define MANGLED_CREATE_AIRFOIL3 "?CreateAirfoil3@VESSEL@@QBEPAXW4AIRFOIL_ORIENTATION@@ABTVECTOR3@@P6AXPAV1@NNNPAXPAN44@Z3NNN@Z"


// ==============================================================
// Type definitions

struct Airfoil {
	AIRFOILHANDLE handle;
	void * vesselInstance;
};


// ==============================================================
// Global variables

void * OrigCreateAirfoil2;
void * OrigCreateAirfoil3;
std::vector <Airfoil> AirfoilList;


// ==============================================================
// Hook functions
// - in original __thiscall functions `this` pointer is passed in ECX register
// - arguments in __fastcall: `pThis` is in ECX register, `unused` in EDX

AIRFOILHANDLE __fastcall CreateAirfoil2Hook (void * pThis, UINT unused, AIRFOIL_ORIENTATION align, const VECTOR3 & ref, AirfoilCoeffFunc cf, double c, double S, double A) {
	AIRFOILHANDLE hAirfoil = ((AIRFOILHANDLE (__fastcall *)(void *, UINT, AIRFOIL_ORIENTATION, const VECTOR3 &, AirfoilCoeffFunc, double, double, double)) OrigCreateAirfoil2)(pThis, unused, align, ref, cf, c, S, A);
	if (hAirfoil) {
		Airfoil airfoil = {hAirfoil, pThis};
		AirfoilList.push_back (airfoil);
	}
	return hAirfoil;
}


AIRFOILHANDLE __fastcall CreateAirfoil3Hook (void * pThis, UINT unused, AIRFOIL_ORIENTATION align, const VECTOR3 & ref, AirfoilCoeffFuncEx cf, void *context, double c, double S, double A) {
	AIRFOILHANDLE hAirfoil = ((AIRFOILHANDLE (__fastcall *)(void *, UINT, AIRFOIL_ORIENTATION, const VECTOR3 &, AirfoilCoeffFuncEx, void *, double, double, double)) OrigCreateAirfoil3)(pThis, unused, align, ref, cf, context, c, S, A);
	if (hAirfoil) {
		Airfoil airfoil = {hAirfoil, pThis};
		AirfoilList.push_back (airfoil);
	}
	return hAirfoil;
}


// ==============================================================
// Hooking/Unhooking function
// - you need to pass the mangled function name like it's exported in orbiter.exe
// - returns previous/original address of the hooked function after successful hooking

void * HookOrbiterFunction (const char * mangledFuncName, const void * hookAddr) {
	HINSTANCE orbiterInst = oapiGetOrbiterInstance ();

	IMAGE_DOS_HEADER * DOSHeader = (IMAGE_DOS_HEADER *)orbiterInst;
	if (DOSHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL;

	IMAGE_NT_HEADERS * NTHeader = (PIMAGE_NT_HEADERS)((DWORD)DOSHeader + (DWORD)DOSHeader->e_lfanew);
	if (NTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL;

	IMAGE_EXPORT_DIRECTORY * orbiterEAT = (IMAGE_EXPORT_DIRECTORY *)((DWORD)orbiterInst + (DWORD)NTHeader->OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

	for (DWORD i = 0; i < orbiterEAT->NumberOfFunctions; ++i) {
		DWORD * pFuncNameOffset = (DWORD *)((DWORD)orbiterInst + (DWORD)orbiterEAT->AddressOfNames + i * sizeof (DWORD));

		if (strcmp ((char *)((DWORD)orbiterInst + *pFuncNameOffset), mangledFuncName) == 0) {
			WORD * addrOfNameOrd = (WORD*)((DWORD)orbiterInst + (DWORD)orbiterEAT->AddressOfNameOrdinals + i * sizeof (WORD));
			DWORD * addrOfFunc  = (DWORD*)((DWORD)orbiterInst + (DWORD)orbiterEAT->AddressOfFunctions + *addrOfNameOrd * sizeof (DWORD));

			DWORD oldAccessMode;
			if (!VirtualProtect (addrOfFunc, sizeof (DWORD), PAGE_READWRITE, &oldAccessMode)) return NULL;
			void * origAddr = (void *)(*addrOfFunc + (DWORD)orbiterInst);
			*addrOfFunc = ((DWORD)hookAddr - (DWORD)orbiterInst);
			if (!VirtualProtect (addrOfFunc, sizeof (DWORD), oldAccessMode, &oldAccessMode)) return NULL;
			return origAddr;
		}
	}
	return NULL;
}


// ==============================================================
// Module interface

class AirfoilHookingModule : public oapi::Module {
public:
	AirfoilHookingModule (HINSTANCE hDLL) : oapi::Module (hDLL) {
		// Hook functions
		OrigCreateAirfoil2 = HookOrbiterFunction (MANGLED_CREATE_AIRFOIL2, &CreateAirfoil2Hook);
		OrigCreateAirfoil3 = HookOrbiterFunction (MANGLED_CREATE_AIRFOIL3, &CreateAirfoil3Hook);
	}

	~AirfoilHookingModule () {
		// Unhook functions
		if (OrigCreateAirfoil2) {
			HookOrbiterFunction (MANGLED_CREATE_AIRFOIL2, OrigCreateAirfoil2);
			OrigCreateAirfoil2 = NULL;
		}
		if (OrigCreateAirfoil3) {
			HookOrbiterFunction (MANGLED_CREATE_AIRFOIL3, OrigCreateAirfoil3);
			OrigCreateAirfoil3 = NULL;
		}
	}

	void clbkDeleteVessel (OBJHANDLE hVessel) {
		void * vesselInterface = (void *)oapiGetVesselInterface (hVessel);
		for (std::vector <Airfoil>::iterator airfoil = AirfoilList.begin (); airfoil != AirfoilList.end (); ++airfoil) {
			if (airfoil->vesselInstance == vesselInterface) airfoil = AirfoilList.erase (airfoil);
		}
	}

	void clbkSimulationEnd () {
		AirfoilList.clear ();
	}

} * airfoilHookingModule;


// ==============================================================
// DLL entry and exit points

DLLCLBK void InitModule (HINSTANCE hDLL) {
	airfoilHookingModule = new AirfoilHookingModule (hDLL);
	oapiRegisterModule (airfoilHookingModule);
}


DLLCLBK void ExitModule (HINSTANCE hDLL) {
	delete airfoilHookingModule;
}
Hooked functions add newly created airfoil handles and their associated vessel instances to a vector. They are removed from the vector either when the associated vessel is deleted or when simulation ends.
 
Top