Jump to content

JasonMel

Members
  • Posts

    3
  • Joined

  • Last visited

Personal Information

  • Location
    florida
  • Interests
    aviation
  • Occupation
    bit tinkerer

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Hey all (and @ivanwfr), The renewed interest by @dmonds made me curious enough to try again to make DLL calls, and I did actually get it to work this time. Here's how I did it: 1. Compile a simple C++ project to a DLL in Visual Studio, such as one consisting entirely of this .cpp source file: extern "C" __declspec(dllexport) int __stdcall TestFunction() { return 42; } I created a few solutions, but some resulting DLLs were accepted as plugins and some were not, when plopped into the Plugins folder. When it's accepted, you'll see "Loaded plugin module <full path to DLL>" when opening the script editor. I'm not sure whether the DLL needs to be accepted this way, or whether it even needs to be in the Plugins folder at all. It does not seem to matter that compiling produces the message "Failed to map plugin module <full path to DLL>" since, as we'll see, we can accomplish the mapping step in code. It's very possible that TARGET will be finicky about the compiler options used to build the DLL, and we can work out which ones are important. 2. Create a simple, bare-bones TARGET script, such as this one: include "target.tmh" int fonctionne(){} //program startup int main() { if(Init(&EventHandle)) return 1; // declare the event handler, return on error printf( "Hello world!\xa"); int lib = LoadLibrary("LibraryLoadTest.dll"); printf( "Library address: %d\xa", lib ); int funk = GetProcAddress(lib, "_TestFunction@0"); printf( "Library function address: %d\xa", funk ); int mapped = Map(&fonctionne, funk, MAP_IPTR_VPN); // returns object. mode:MAP_NORMAL=1, MAP_IPTR=2, MAP_IPTR_VPN=3, MAP_THISCALL=4 printf( "Mapped function address: %d\xa", mapped ); printf( "%d", fonctionne(), "\xa"); //add initialization code here } //event handler int EventHandle(int type, alias o, int x) { DefaultMapping(&o, x); //add event handling code here } You don't really need all the print statements, of course, and I'm sure you don't need to save the address returned by Map(). But if all goes well, you should see the number 42 in the editor's output window after the three large integer addresses. The string "_TestFunction@0" can be discovered by running >dumpbin /EXPORTS <DLL file>. I tried unsuccessfully to compose the C++ in such a way that the exported function name is simply the same as in the source file, but there may be a way to do that. I was so close before. I don't know why it took a three-year gap to hit on the right syntax. I certainly wish the jerks at ThrustMaster had made this procedure more clear. It wouldn't have taken much.
  2. Hey, thanks, Ivan! I've put the .dll into \Plugins, which causes the editor to say this when launching itself and then compiling my script: Loaded plugin module "C:\Program Files (x86)\Thrustmaster\TARGET\Plugins\sys.dll" Loaded plugin module "C:\Program Files (x86)\Thrustmaster\TARGET\Plugins\UnmanagedLink.dll" Compiling script: Axis Swap.tmc Mapped plugin module "C:\Program Files (x86)\Thrustmaster\TARGET\Plugins\sys.dll" Failed to map plugin module "C:\Program Files (x86)\Thrustmaster\TARGET\Plugins\UnmanagedLink.dll" ! Compile Succeeded. Here's how the .cpp file that compiles to UnmanagedLink.dll defines the exported function: extern "C" __declspec(dllexport) int __cdecl ShowAxisMessage() {...} That function is the only unmanaged code in the file, but as I mentioned, it's a CLI project, so there's a managed C++ namespace with a class that ShowAxisMessage() calls into. I'm running Visual Studio 2022 Community, toolset v143. I tried recompiling it using both __stdcall and __cdecl conventions, and I tried calling both ShowAxisMessage() and _ShowAxisMessage() in the TARGET code (_ShowAxisMessage@0() causes a compile error). I'm compiling the .dll in Debug x86 mode, and optimizations are turned off. There's a bunch of project options I'm not familiar with, but I do have a couple configured, like I have "Not Using Precompiled Headers" and "Common Language Runtime Support" set. Under C++ > Language, I have "Conformance mode" set to default, since it won't compile in the default "/permissive-" mode (it complains about "two-phase name look-up"). Could it matter that I have it set to the default of "ISO C++14 Standard"? I only have C++14, C++17, and C++20 as options. The fact that it says "Failed to map" suggests that I may have been on the right track when I tried to put Map() and MakeProcInstance() together like target.tmh does. I read a bit about MakeProcInstance online. It's ... arcane. I'm really a novice when it comes to Windows assemblies and interop.
  3. Hey, folks. I hope you don't mind me asking here, but on the (currently somewhat inactive) subject of advanced TARGET programming: Has anyone managed to load a DLL and call an exported function in it? I've been banging my head on this for a while. I have a Visual Studio C++/CLI project that exports a function to display joystick mode information, and I'm just trying to call that function with a T.16000M FCS joystick button. I haven't had any luck so far. I appear to be able to load the DLL and get the address of the exported function: int LoadMyLibrary() { int lib = LoadLibrary("UnmanagedLink.dll"); if (lib == 0) { printf("Bad library address\xa"); return 0; } int procAddr = GetProcAddress(lib, "_ShowAxisMessage@0"); // found with >dumpbin /EXPORTS if (procAddr == 0) { printf("Bad proc address\xa"); return 0; } lib and procAddr seem to have good numbers in them, and no error is generated. However, I haven't been able to figure out how to call the darned thing. I can call existing TARGET functions with an alias, like so: int printMsg () { printf("This is a message.\xa"); } int aliasMsg () { alias repeat = &printMsg; repeat(); // this works } It's getting the loaded procedure address into the alias and calling it that's got me stumped. I've tried various combinations of Map(), MakeProcInstance(), realloc(), setmem(), execute(), eval(), and have reached the desperation point. For example, this seems like it should work in LoadMyLibrary(), but it doesn't: alias ShowMsg; &ShowMsg = procAddr; ShowMsg(); // Bad alias It doesn't work any better if ShowMsg() is defined outside LoadMyLibrary(): int ShowMsg() {} int LoadMyLibrary() { // get procAddr as above &ShowMsg = procAddr; // Bad alias ShowMsg(); } I don't really know what constitutes a good or bad alias. There's a lot of this pattern in target.tmh: Map(&CHAIN, MakeProcInstance(&_CHAIN), MAP_IPTR_VPN), but MakeProcInstance(procAddr) doesn't work because procAddr isn't an alias, and so would generate another "bad alias" runtime error on that line. I feel like someone somewhere must know how to use these TARGET library-related functions. Any ideas?
×
×
  • Create New...