从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 ?
你的意思肯定是:
#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项目汇编暴露函数,而无需注意后面调用的本机代码。