从dll调用本机方法

本文关键字:方法 本机 调用 dll | 更新日期: 2023-09-27 18:06:26

我试图在c++/CLI项目的混合模式中使用MimeTex.dll。我通过以下方式包含dll:#pragma comment(lib,"MimeTex.dll")

,我试着调用这个方法:CreateGifFromEq("expression","path");

但是编译器通知它不知道CreateGifFromEq()方法

我没有在网上找到如何在c++中使用MimeTex.dll的资源。我只是在Pinvok的这个链接中找到了如何在c#中使用它,比如:

[System.Security.SuppressUnmanagedCodeSecurity()]
internal class NativeMethods
{
    private NativeMethods()
    { //all methods in this class would be static
    }
    [System.Runtime.InteropServices.DllImport("MimeTex.dll")]
    internal static extern int CreateGifFromEq(string expr, string fileName);
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    internal extern static IntPtr GetModuleHandle(string lpModuleName);
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
    internal extern static bool FreeLibrary(IntPtr hLibModule);
}

,然后命名为:

NativeMethods.CreateGifFromEq(equation, tempGifFilePath);

如何在c++/CLI的混合模式下调用它而不使用Pinvok ?

从dll调用本机方法

你的意思肯定是:

#pragma comment(lib,"MimeTex.lib")

换句话说,您将.lib文件传递给链接器而不是.dll。当您编译DLL时,将生成一个.lib文件。

但这不是你当前的问题。编译器没有CreateGifFromEq的声明。这是因为您没有在c++代码中包含库的头文件。这样做应该可以解决问题。

如果你需要的只是一个函数,那么在你的c++代码中声明它应该是微不足道的。

__declspec(dllimport) extern int CreateGifFromEq(char *expr, char *fileName);

你可能也需要在extern "C"块中包装它。

实际上,查看了库后,随源代码提供的头文件没有声明该函数,即使它存在于库中。

在c++/CLI中,您可以像在c#中一样使用p/Invoke。

如果你不想使用p/Invoke,另一种方法是使用LoadLibrary加载DLL,并使用GetProcAddress获取指向函数的指针。


下面是c++/CLI中对应的c#代码:

using namespace System;
using namespace System::Runtime::InteropServices;
private ref class NativeMethods abstract sealed
{
internal:
    [DllImport("MimeTex.dll")]
    static int CreateGifFromEq(String^ expr, String^ fileName);
    [DllImport("kernel32.dll")]
    static IntPtr GetModuleHandle(String^ lpModuleName);
    [DllImport("kernel32.dll")]
    [returnvalue: MarshalAs(UnmanagedType::Bool)]
    static bool FreeLibrary(IntPtr hLibModule);
};

正如你所看到的,它几乎与c#代码相同,除了一些小的语法变化。

下面是如何使用LoadLibrary和GetProcAddress(其优点是不需要封送处理,这在c++中是不必要的):

HMODULE hModule = LoadLibrary(L"MimeTex.dll");
int (*fpCreateGifFromEq)(WCHAR*, WCHAR*) = GetProcAddress(hModule, "CreateGifFromEq");
(*fpCreateGifFromEq)(L"expression", L"filename");

你不需要为GetModuleHandle和FreeLibrary这样做,因为它们来自kernel32.dll,所以你可以只包含Windows.h并正常调用它们

有一种更简洁的方法:

创建c++/CLI项目。它将是你的c#和c++之间的接口(这是c++/CLI的目标)。

让你的c#项目有一个对这个新程序集的引用。

在新的c++/CLI项目中,配置项目选项,以便指向包含mimetex .h文件的目录,供编译器编译项目,指向包含.lib/.dll文件的目录,供链接器编译。

在c++/CLI部分中,您只需在函数中编写c++即可。它们暴露在c#程序集中,但在内部,它只是像往常一样调用c++函数。(您应该查看c++ CLI教程,以了解如何将字符串转换为本机char或std::string。我记得我必须看一下。)*

在c#部分中,您只需像普通c#函数一样调用c++ CLI项目汇编暴露函数,而无需注意后面调用的本机代码。