Jump to content

Issues with DllImport when not on Windows

Recommended Posts

I am dependent on an external DLL to perform some functionality for my plugin. To do this I use P/Invoke's DllImport and it works all fine on Windows. When on Linux/OSX, however, a DllNotFoundException is thrown. (I am using dedicated mac/linux libs when appropriate)

[EXC 13:45:27.864] DllNotFoundException: osx/discord-rpc.bin
	DiscordRP.Discord.OSXInvoker.Initialize (System.String applicationId, .EventHandlers& handlers, Boolean autoRegister, System.String optionalSteamId)
	DiscordRpc.Initialize (System.String applicationId, .EventHandlers& handlers, Boolean autoRegister, System.String optionalSteamId)
	DiscordRP.Discord.PresenceController.Initialize ()
	DiscordRP.DiscordRPMod.Start ()

The file definitely exists, so this error can only mean some other issue occurred while loading was attempted.

Windows imports: https://github.com/gegy1000/KSP-DiscordRP/blob/master/DiscordRP/Discord/Win64Invoker.cs#L33-L46

OSX imports: https://github.com/gegy1000/KSP-DiscordRP/blob/master/DiscordRP/Discord/OSXInvoker.cs#L33-L46

Used library files: https://github.com/discordapp/discord-rpc/releases/tag/v2.1.1

I'm quite lost as to what's going on here -- so any help would be appreciated! :)

Link to comment
Share on other sites

8 minutes ago, sarbian said:

Where do you put your libs in KSP ? With GCMon when it used libs I imported with the full path from ksp exe ( https://github.com/sarbian/GCMonitor/blob/5547e8325a2ed09321af52ebcc3e4830ced2c26b/GCMonitor.cs#L159-L178 )

I scan for them in the plugin directory: https://github.com/gegy1000/KSP-DiscordRP/blob/master/DiscordRP/DiscordRPMod.cs#L27-L28

Link to comment
Share on other sites

14 hours ago, sarbian said:

Where do you put your libs in KSP ? With GCMon when it used libs I imported with the full path from ksp exe ( https://github.com/sarbian/GCMonitor/blob/5547e8325a2ed09321af52ebcc3e4830ced2c26b/GCMonitor.cs#L159-L178 )

Alright, following what you did there by referencing from GameData, it works! I guess that means editing the PATH was at fault. Thanks for the help. :)

Link to comment
Share on other sites

  • 2 months later...

Edit: @Sarbian: This post might be of interest for you also!

Edit2: I just tested renaming all the files.  I added .dat on the end of each filename, and did the same in the dll-map, and it works as expected.

I realise you have solved all your problems but I've just recently dredged up my old modding files and got them running in the latest KSP and thought I would share something that I figured out for cross-platform external-library KSP/Unity development that might help you.  (For context my mod was a variation on the various engine-balancing mods that existed back then, and still exist, ThrottleControlledAvionics [aka TCA] which still exists!)

So; I learned this initially because KSP when I started modding was primarily a 32 bit application; with only a beta 64 bit branch; so I wanted to have a single list of function imports that worked for 32 and 64 bit applications; and I had a mac so I wanted to look at loading the library on that platform also.

I found out about a feature that exists only in Mono, known as the "DLL Map"

This allows you to use a single DLL Import, and a "Map" that maps the import to an appropriate library depending on other factors.

I'll use code copy and pasted from my project:

I use a library called LpSolve55, I have 32bit and 64bit modules, and modules for Windows/Mac/Linux, which gives me 6 different files I need to choose from.

I do it like this:

Project: LibSolver (Generates "LibSolver.dll" in my example, replace where appropriate)

Create XML file: LibSolver.dll.config  (MUST be the same name as the DLL that has the DLLImport commands)

Mark it as BuildAction: "Content" and "Copy if Newer" (file must be sitting right next to the DLL)

<?xml version="1.0" encoding="utf-8" ?>
  <!-- DLL map files only work in Mono, hopefully Unity on windows (for KSP) also uses mono. -->

  <!--  OSX  -->
  <dllmap dll="lpsolve55" os="osx" cpu="x86-64" wordsize="64" target="gamedata/AdvancedAvionics/x64/liblpsolve55.dylib" />
  <dllmap dll="lpsolve55" os="osx" cpu="x86" wordsize="32" target="gamedata/AdvancedAvionics/x86/liblpsolve55.dylib" />

  <!-- Linux -->
  <dllmap dll="lpsolve55" os="linux" cpu="x86-64" wordsize="64" target="gamedata/AdvancedAvionics/x64/liblpsolve55.so" />
  <dllmap dll="lpsolve55" os="linux" cpu="x86" wordsize="32" target="gamedata/AdvancedAvionics/x86/liblpsolve55.so" />
  <!-- Windows - Mono only potentially -->
  <dllmap dll="lpsolve55" os="windows" cpu="x86-64" wordsize="64" target="gamedata\AdvancedAvionics\x64\lpsolve55.dll" />
  <dllmap dll="lpsolve55" os="windows" cpu="x86" wordsize="32" target="gamedata\AdvancedAvionics\x86\lpsolve55.dll" />


The file is pretty self explanatory, depending on the architecture it loads a different file.

Then for your actual DLLImport you do something like this:

        [DllImport("lpsolve55", SetLastError = true)]
        public static extern bool add_column(long lp, double[] column);

Note: that the path I use for the DLLImport is the "dll" field in the dllmap file above.  The actual Config file does the hard work of specifying the path to the platform-specific library.

This allows you to maintain a single DllImport file, which is cross-platform.  Lets you save your DLLs Libs and So's in a folder that makes sense.

I haven't yet tried changing the extension on the DLLs (I'm getting your other error your other post references too) but I don't see why it won't work.

Note; as mentioned in the XML config file, this is Mono specific.  If Unity ever changes to run on something other than Mono (IE on Windows they use DotNet proper?) this will all fall over, and I have no idea how to fix it after that!


There is actually a side benefit from all of the above.  If the basic library remains the same, but an updated version comes out, or a bug-fix and for some reason, or it relies on an operating system DLL that lives in a specific path, the dll-config file is editable by users, without needing to recompile the whole project.

IE people can update files; or perhaps add their own for an architecture you don't currently have a native library for.  As long as the DLL exports the same functions someone else can get a library that works; and with minimum effort supply it in addition to your existing libraries. (IE you don't list a linux library, but someone might cross-compile one for you, and adding support for it is a simple matter of updating the config file).

PS. turns out I was working on this almost 4 years ago. Sigh.

Edited by MeateaW
More info.
Link to comment
Share on other sites

Yep; at one stage in my development I had 2 different files one for the 64bit library and one for the 32 bit library and then a "shim" that would pick which library to call depending on the operating system.

As soon as I started thinking about mac-os support I realised it started to balloon out, instead of a simple "if 64bit" shim, I needed to add in functions to detect operating system.  And I hadn't even considered the Linux OS at that point.

It didn't help that the library I was using had on the order of 200 exported functions that I was trying to import.  ~600 lines of code for each operating system/architecture combination just to import the files was a bit of a waste.

I went down a very deep rabbit hole of DLL loading paths and functions (most of them DotNet related, not Mono) until I found some forum post about someone asking for DotNet to implement something similar to the "dllmap" feature of Mono.  It was a lucky find that led me to the above solution.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...