在进行C++到C#类型转换时出现了“无法找到dll中名为[function]的入口点”的错误。

28

我有一个来自第三方的dll,它是用C ++编写的。 这里是一些来自dll文档的信息:

//start documentation

RECO_DATA{
wchar_t Surname[200];
wchar_t Firstname[200];
}

描述:

用于接收函数结果的数据结构。所有函数结果都将以Unicode(UTF-8)的形式存储。

方法:

bool recoCHN_P_Name(char *imgPath,RECO_DATA *o_data);

输入:

char * imgPath

此功能识别图像位置的完整路径

RECO_DATA * o_data

数据对象用于接收函数的返回结果。 函数返回值: 成功返回 True,否则返回 False。

//end documentation

我想从我的C#应用程序中调用recoCHN_P_Name。为此,我编写了以下代码:

导入dll的代码:

    public class cnOCRsdk
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct RECO_DATA{
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=200)]
        public string FirstName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
        public string Surname;
        }

    [DllImport(@"cnOCRsdk.dll", EntryPoint="recoCHN_P_Name")]
    public static extern bool recoCHN_P_Name(byte[] imgPath, RECO_DATA o_data);
}

调用该函数的代码:
            cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();

        string path = @"C:\WINDOWS\twain_32\twainrgb.bmp";

        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        byte[] bytes = encoding.GetBytes(path);

        bool res = cnOCRsdk.recoCHN_P_Name(bytes, recoData);

我遇到的错误是: ""无法在DLL“cnOCRsdk.dll”中找到名为“recoCHN_P_Name”的入口点。" 我怀疑在将C++类型转换为C#时出现了错误。但具体在哪里呢...?

10个回答

49

首先要确保该函数已经被导出:

在Visual Studio命令提示符中,使用dumpbin /exports whatever.dll命令。


输出中有一行是这样的:“14 D 00007B40 ?recoCHN_P_Name@CcnOCRsdk@@QAE_NPADPAURECO_DATA@@@Z”这告诉我什么? - Evgeny
3
请参考http://www.kegel.com/mangle.html以获取详细的解密说明。确保数据类型正确。 - i_am_jorf

32

C#不支持C++的命名修饰,你需要使用

extern "C" {...}

(如果它们来自第三方,则可能不是选项),或者直接调用混淆名称(mangled name),如果您可以让它正常工作的话。更容易让第三方提供非混淆接口来实现功能。


这就是我的情况了,谢谢! - Israel Unterman

19

问题已解决 - 至少程序不会崩溃并能返回一个布尔值。

我猜关键是要将入口点指定为“mangled”名称。

    [DllImport(@"cnOCRsdk.dll", EntryPoint="?recoCHN_P_Name@CcnOCRsdk@@QAE_NPADPAURECO_DATA@@@Z")]
    public static extern bool recoCHN_P_Name(ref string imgPath, ref RECO_DATA o_data);

之后我遇到了其他一些错误,但是“无法找到入口点”的错误消失了。


1
这个方法可以工作,但是如果函数(签名)的任何内容发生变化,你必须更改混淆的名称。建议在DLL中使用extern "C"来定义它们,如上所述。 - adam_0
@Goku,你可以使用一个叫做PE Explorer的程序(http://www.heaventools.com/overview.htm)或者Visual Studio自带的dumpbin.exe程序来找到它。 - Ryan Griffith

7

我通过以下步骤解决了同样的问题:

第一步) 如果您使用Visual Studio在C++中编写自定义DLL,则在项目的属性页上将Common Language Runtime Support (/clr)参数设置为Common Language Runtime Support (/clr)

第二步).h文件中的函数声明中使用__declspec(dllexport)关键字,如下所示:

__declspec(dllexport) double Sum(int a,int b);

步骤3) 构建并导出DLL文件,然后使用Dependency Walker软件获取您的函数EntryPoint

步骤4) 在C#项目中导入DLL文件,并设置EntryPointCallingConvention变量,如下所示:

[DllImport("custom.dll", EntryPoint = "?Sum@@YAXHHHHHHNNN@Z", CallingConvention = CallingConvention.Cdecl)]

    public static extern double Sum(int a,int b);

__declspec(dllexport) 对我来说非常关键,另一个答案中的人们将它们标记为 extern "C",但是什么也没有被导出,谢谢! - fartwhif
谢谢!我看到了大约10个解决方案,建议使用“extern C”以及“__declspec(dllexport)”。C++编译器无法使用extern,但我无法弄清原因。这对我来说第一次就奏效了。 - GrandMasterFlush

4

我会编写一个使用C++/CLI的包装器。这个包装器可以包含从第三方供应商获取的.h文件和链接到.lib文件。然后,编写一个管理接口供您的C#程序使用既容易又安全。


2

在主要的非托管dll文件所附带的“.lib”文件中可以找到正确的EntryPoint字符串。


1

你可能会因为DLL和应用程序之间的字符串编组不匹配而遇到此错误。例如,一个使用ANSI编码,另一个使用Unicode编码。

你可以尝试像这样做:

 [DllImport("yourDLL.dll", CharSet = CharSet.Unicode )]
 public static extern String YourFunction(String name);

请查看此处,了解其他可能的原因列表。


1
我们在访问数据库时遇到了这个问题,通过将 EF Core 更改为 EF 6.4.4 解决了它。如果您也遇到了类似的问题并且使用了 EF,则可能需要更改或降级您的 EF 版本。请注意,不要删除任何 HTML 标签。

0
我们遇到了这个问题。我们将EntityFramework.Core更改为EntityFrameWork 6.4.4,之后程序就正常工作了。你必须更改你的框架版本。

-1
您可以尝试在 DllImport 中指定 CallingConvention 并使用未混淆的名称。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接