繁体   English   中英

我可以从.Net Core调用来自kernel32.dll的LoadLibrary()的Linux等效模块和function吗?

[英]Is there a Linux equivalent module and function for LoadLibrary() from kernel32.dll that i can call from .Net Core?

我正在将 a.Net Core 3.1 应用程序从 windows 移植到 Linux。 我在 windows 上有一个 ourdevice.dll,以及为 Linux 构建的等效 ourdevice.so。 这个 dll 是一个原生 dll,我们在 windows 上使用了一个 pinvoke 包装器。

我们使用来自 kernel32.dll 的 DllImports 从本机 dll 加载函数

    [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)]
    public static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);

我们为要导入的每个函数创建代表:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate short AdcOpen([MarshalAs(UnmanagedType.LPStr)] string adcName, [MarshalAs(UnmanagedType.LPStr)] string protocol, [MarshalAs(UnmanagedType.LPStr)] string port, ref short handle, byte performSwReset);
    private AdcOpen adcOpen;

然后我们 map 所有的本机函数是这样的:

        IntPtr pAddressOfFunction;

        pDll = LoadLibrary(LibraryName);

        // check if library is loaded
        if (pDll != IntPtr.Zero)
        {
            // get proc address of the native functions
            pAddressOfFunction = GetProcAddress(pDll, "AdcOpen");
            if (pAddressOfFunction != IntPtr.Zero)
                adcOpen = (AdcOpen)Marshal.GetDelegateForFunctionPointer(pAddressOfFunction, typeof(AdcOpen));
            else
                message += "Function AdcOpen not found\n";
          
            //snip loading all the exported functions

        }

在 Linux 应用程序中,显然我们不能使用 kernel32.dll。 我们在 Linux 上的.Net 内核中编写 C#,我们有本机模块ourdevice.so。 如何将本机 Linux 模块中的函数导入到我们的 C# 包装器中? 甚至可能吗?

几个想法。

首先,是的, DllImport (P/Invoke)也适用于 Linux(和 macOS)。

这似乎有点奇怪:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate short AdcOpen([MarshalAs(UnmanagedType.LPStr)] string adcName, [MarshalAs(UnmanagedType.LPStr)] string protocol, [MarshalAs(UnmanagedType.LPStr)] string port, ref short handle, byte performSwReset);
    private AdcOpen adcOpen;

使用映射代码( LoadLibraryGetProcAddressFreeLibrary ),这似乎是您手动执行 .NET 本身所做的工作,如果您执行此类操作 - 您让 .NET 执行 ZC1C425268E68385D1AB507

    [DllImport("ourdevice.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern short AdcOpen([MarshalAs(UnmanagedType.LPStr)] string adcName, [MarshalAs(UnmanagedType.LPStr)] string protocol, [MarshalAs(UnmanagedType.LPStr)] string port, ref short handle, byte performSwReset);

这样做有什么不同的理由吗?

因为如果你这样做,我希望 Linux 版本看起来像这样,并且工作方式与 Windows 几乎相同:

    [DllImport("libourdevice.so", CallingConvention = CallingConvention.Cdecl)]
    private static extern short AdcOpen([MarshalAs(UnmanagedType.LPStr)] string adcName, [MarshalAs(UnmanagedType.LPStr)] string protocol, [MarshalAs(UnmanagedType.LPStr)] string port, ref short handle, byte performSwReset);

假设您使用相同的调用约定和参数编组。 唯一的区别是名称从"ourdevice.dll"更改为"libdevice.so" 您还需要将libdevice.so放在可以找到的地方; 应用程序可执行文件旁边应该可以工作。

如果您仍想通过LoadLibrary / GetProcAddress / FreeLibrary方法手动执行此操作,则可以使用 Linux 上的大致等效方法:

  • dlopen (类似于LoadLibrary
  • dlsym (类似于GetProcAddress
  • dlclose (类似于FreeLibrary

有关如何使用这些方法的示例和示例代码,请参阅https://stackoverflow.com/a/13492645/3561275

加载库:

[DllImport("libdl", ExactSpelling = true)]
public static extern IntPtr dlopen(string filename, int flags);

获取过程地址:

[DllImport("libdl", ExactSpelling = true)]
public static extern IntPtr dlsym(IntPtr handle, string symbol);

免费图书馆:

[DllImport("libdl", ExactSpelling = true)]
public static extern int dlclose(IntPtr handle);

示例用法:

const int RTLD_NOW = 0x002;
IntPtr pDll = dlopen("ourdevice.so.0", RTLD_NOW);
IntPtr pAddressOfFunction = dlsym(pDll, "AdcOpen");
...
dlclose(pDll);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM