c# - 在C#Windows应用程序中使用C++ DLL:获取错误 “Entry point not found”

标签 c# c++ dllimport dependency-walker

我对使用C#中的C++库以及一般的C++编程是不熟悉的。我有一个从C++代码构建的DLL,我相信它是“托管”代码,因为DLL的名称是“TestManaged.dll”。我不是100%确定dll / C++代码是否为托管/非托管。

我想在我的C# windows forms application代码中使用此DLL的类和方法。此DLL中有多个类。当我在Object Browser的这些类中检查这些类和方法时,它们全部都有Public标识符。

到目前为止,我已将此DLL添加到C#应用程序代码的引用中。我将在问题中讨论三个类:ProductReqStatusProductData。我可以为此DLL的各种类创建一个或多个对象,如下所示。

Product testCall = new ProductClass();

在此DLL中还有另一个名为ProductData的类,我可以为该类获取C++代码,如下所示。在这种情况下,ProductData在C#中的Object Browser中显示为类,因为它实际上是C++代码中的结构。我不确定这对回答我的问题是否重要(最后)。

以下是定义ProductData结构-ProductData.h文件的C++代码。
#ifdef WIN32_MANAGED 
public ref  struct ProductData
#else
struct ProductData
#endif
{
    UINT32 ProductId;           //!< Product ID    
    UINT32 PRoductRev;         //!< Build Revision
};

以下是定义ReqStatus枚举-ReqStatus.h文件的C++代码。我在C#代码中创建了相同的枚举,但未指定标识符。
enum ReqStatus
{
    SUCCESS,            //!< Method was successful

    //Connection errors
    NOT_CONNECTED,      //!< Connection not open 
    CONN_TIMEOUT,       //!< Connection timed out commuincating with device
};

现在,我有两种方法要调用,但都存在问题:

方法1:是getProductData类中的Product方法,该方法接受ProductData类型的对象作为参数,并返回C++中为枚举类型的ReqStatus。因此,下面是gerProductData方法的声明(如Object Browser所示):
public ReqStatus getProductData(ProductData data)

相同方法的C++替代方法是:(实际方法太长,因此仅给出声明):此方法位于Prodcut.cpp文件中
ReqStatus Product::getProductData(ProductData PLATFORM_PTR data)

PLATFORM_PTR在Platform.h中定义如下
#ifdef WIN32_MANAGED
#define PLATFORM_PTR ^
#else
#define PLATFORM_PTR *
#endif

方法2:是getConnected类中的Product方法,它接受字符数组(我不确定)和ProductData类型的对象作为参数,并返回ReqStatus,它是C++中的枚举类型。因此,下面是getConnected方法的声明(如Object Browser所示):
public ReqStatus getConnected(sbyte* someChar, ProductData data)

相同方法的C++替代方法是:(实际方法太长,因此仅给出声明):此方法位于Prodcut.cpp文件中
ReqStatus Product::getConnected(const char *someChar, ProductData PLATFORM_PTR data)

C++代码按如下方式调用方法:
private : Product^  _testProduct;
testProduct = gcnew Product();
ProductData ^ data = gcnew ProductData();

int portNum = Decimal::ToInt16(7); 
char portName[32];
_snprintf(&portName[0], sizeof(portName),"COM%d", portNum);
ReqStatus status = _testProduct->getConnected(&portName[0], data); //Calling getConnected
getProductData方法内部有一个对getConnected方法的内部调用。
ReqStatus status = getProductData(data); //data is the same which was passed to the getConnected method

我的C#代码如下,在两个方法调用中都出现错误:在下面的代码片段的同一行上放置了错误。两种方法都是独立的。只是从C++代码中的getProductData方法调用了getConnected。我想检查一下是否可以分别打电话给我。
ProductData pData = new ProductData(); // OK
Product _testProduct = new Product();  // OK

ReqStatus status1 = _testProduct.getConnected("COM5", pData ); //Error 1: The best overloaded method getConnected has some invalid arguments
ReqStatus status2 = (ReqStatus)_testProduct.getProductData(pData ); // Error 2: Method is inaccessible due to its protection level

对于错误1,我尝试了StackOverflow和其他论坛上各种文章中的解决方案,但无法解决。仅供参考,我尝试按以下方式更改“SomePortCOM”,但它不起作用。

更新:该代码现在可以正常工作,并且我看不到错误1(无效的参数)。现在,我只需要摆脱错误2(保护级别错误)。请提供任何建议。谢谢。
String str = "COM5";
byte[] bytes = Encoding.ASCII.GetBytes(str);
unsafe
    {
        fixed (byte* p = bytes)
        {
                sbyte* sp = (sbyte*)p;
                //SP is now what you want
                   ReqStatus status1 = _testProduct.getConnected(sp, pData );
        }
    }

对于Error2,我搜索了很多博客,发现可能的解决方案之一可能是使用DLLImport,我也尝试过这样做,但遇到以下问题:

DLLImport的C#声明:
[DllImport("TestManaged.dll",EntryPoint="getConnected")]
        public static extern ReqStatus getConnected(String SerialPort, ref ProductData pData);

我从我的C#代码中调用此函数,如下所示:
ProductData pData = new ProductData();
String str = "COM7";
ReqStatus status1 = getConnected(str, ref pData);

但是,我收到了Entry point not found错误。我试图运行dumpbin函数来获取此DLL导出的函数列表。但是,我看不到任何功能。而是如下所示的随机输出。
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Rumit\TestManaged.dll

File Type: DLL

  Summary

        2000 .data
       22000 .rdata
        1000 .reloc
        1000 .rsrc
       13000 .text

更新:
另外,我没有通过Dependency Walker在此DLL中看到任何方法。
现在,我已经获得了C++的源代码。但是我对C++编码还是相当陌生。如果需要对C++代码进行任何更改,请给出说明。


问候,
鲁米特

最佳答案

 enum ReqStatus

那是你最大的困扰。声明了本机枚举类型,它在托管代码中不可用,并使使用它的任何代码不可访问。您必须使用enum class关键字声明其托管版本,如下所示:
public enum class ReqStatus {
    // etc...
}

关于c# - 在C#Windows应用程序中使用C++ DLL:获取错误 “Entry point not found”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15508310/

相关文章:

c++ - 基于clang的跨平台C++ IDE?

c# - 如何使用 DLLImport 将字符串从 C# 传递到 C++(以及从 C++ 到 C#)?

c# - 如何提高 C# 对象映射代码的性能

c# - 与 Exchange 服务器集成

c++ - 从文件读取时如何创建对象 vector ? [C++]

c++ - 模板模板参数访问

c# - 将 char 数组从 c# 传递到 c++ dll

.net - 即使 dll 与可执行文件位于同一文件夹中,DllImport 也找不到 dll

c# - 如何在 C# 中使用带有 ProtectSection 方法的 RsaProtectedConfigurationProvider 创建可导出的 RSA key

c# - 在 Umbraco 中对用户隐藏内容选项卡