Failed to import DLL loaded by .NET Core 3.0

-1

I have a .NET Core 3 project which uses a wrapper library that uses Mosquitto to talk with a MQTT Broker.

The wrapper is defined as:

public static class MosquittoWrapper
  {
    public const string MosquittoDll = "mosq";

    [StructLayout(LayoutKind.Sequential)]
    public struct mosquitto_message
    {
      public int mid;
      public string topic;
      public byte[] payload;
      public int payloadlen;
      public int qos;
      [MarshalAs(UnmanagedType.U1)]
      public bool retain;
    }

    public delegate void ConnectCallbackDelegate(int result);
    public delegate void MessageCallbackDelegate(mosquitto_message mesage);

    [DllImport(MosquittoDll, CallingConvention = CallingConvention.Cdecl)]
    public static extern int mosq_init();

    [DllImport(MosquittoDll, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    internal static extern int mosq_set_tls_psk(string psk, string identity, string? ciphers);

    [DllImport(MosquittoDll, CallingConvention = CallingConvention.Cdecl)]
    internal static extern void mosq_set_callback(ConnectCallbackDelegate? connect_callback, MessageCallbackDelegate? message_callback);

    [DllImport(MosquittoDll, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    internal static extern int mosq_connect(string host, int port, int keepalive);

    [DllImport(MosquittoDll, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    internal static extern int mosq_subscribe_topic(string topic);

    [DllImport(MosquittoDll, CallingConvention = CallingConvention.Cdecl)]
    internal static extern void mosq_runloop(int timeout, int max_packets, int sleep_on_reconnect);

    [DllImport(MosquittoDll, CallingConvention = CallingConvention.Cdecl)]
    internal static extern int mosq_destroy();
  }

And the header is defined as:

#pragma once

#ifndef MOSQUITTO_H_
#define MOSQUITTO_H_

#include <mosquitto.h>

#ifdef _WIN32
#    ifdef LIBRARY_EXPORTS
#        define LIBRARY_API __declspec(dllexport)
#    else
#        define LIBRARY_API __declspec(dllimport)
#    endif
#elif
#    define LIBRARY_API
#endif


typedef void (*CONNECT_CALLBACK)(int);
typedef void (*MESSAGE_CALLBACK)(const struct mosquitto_message*);

// return value 0 represents success. Or ENOMEM, EINVAL when error.
LIBRARY_API int mosq_init();
LIBRARY_API int mosq_set_tls_psk(char* psk, char* identity, char* ciphers);
LIBRARY_API void mosq_set_callback(CONNECT_CALLBACK connect_callback, MESSAGE_CALLBACK message_callback);
LIBRARY_API int mosq_connect(char* host, int port, int keepalive);
LIBRARY_API int mosq_subscribe_topic(char* topic);
LIBRARY_API void mosq_runloop(int timeout, int max_packets, int sleep_on_reconnect);
LIBRARY_API int mosq_destroy();

#endif // MOSQUITTO_H_

The issue is when I tried to start the project, .NET Core throws an exception. System.DllNotFoundException: 'Unable to load DLL 'mosq' or one of its dependencies: The specified module could not be found. (0x8007007E)'

This doesn't make sense at all. The dll and its dependencies are copied to the folder which loads mosq dll. Moreover, the running process writes symbol loaded about related dlls explicitly. I also tried to toss the dll around different folders but it's of no use. What could go wrong?

c#
c

1 Answer

1

DLL import in dotnet core works the same as it did in .net framework.

Go to https://mosquitto.org/ and download (source / dll). Here I grab the windows binary "mosquitto.dll".

Generate a C# program with a wrapper for the above dll (API: https://mosquitto.org/api/files/mosquitto-h.html ).

Here I'll just use the init function as a proof of concept

using System;
using System.Runtime.InteropServices;

namespace aac
{
    class Program
    {
        static void Main(string[] args)
        {
            // Just test the init function
            MosquittoWrapper.mosquitto_lib_init();
            Console.WriteLine("success");
        }
    }

    public static class MosquittoWrapper
    {
        // Same name as DLL
        public const string MosquittoDll = "mosquitto";

        // https://mosquitto.org/api/files/mosquitto-h.html#mosquitto_lib_init
        [DllImport(MosquittoDll, CallingConvention = CallingConvention.Cdecl)]
        public static extern int mosquitto_lib_init();
    }
}

Then build the project

PS C:\Users\bburns\code\scratch\aac\aac> dotnet build
Microsoft (R) Build Engine version 16.3.0+0f4c62fea for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 20.94 ms for C:\Users\bburns\code\scratch\aac\aac\aac.csproj.
  aac -> C:\Users\bburns\code\scratch\aac\aac\bin\Debug\netcoreapp3.0\aac.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.61

Then place the mosquitto.dll in the same folder as the executing assembly

 bin\Debug\netcoreapp3.0

Run the program:

PS C:\Users\bburns\code\scratch\aac\aac> dotnet run
success 

Note that if there's a name mis-match or the dll can't be found you'll generate a DllFileNotFoundException.

public const string MosquittoDll = "mosquittoz";

build and run

PS C:\Users\bburns\code\scratch\aac\aac> dotnet run
Unhandled exception. System.DllNotFoundException: Unable to load DLL 'mosquittoz' or one of its dependencies: The specified module could not be found. (0x8007007E)
   at aac.MosquittoWrapper.mosquitto_lib_init()
   at aac.Program.Main(String[] args) in C:\Users\bburns\code\scratch\aac\aac\Program.cs:line 10
answered on Stack Overflow Nov 1, 2019 by BurnsBA

User contributions licensed under CC BY-SA 3.0