在 C# Windows 应用程序中使用 DLL C++:获取错误“找不到入口点”
本文关键字:取错误 获取 找不到 入口 C++ 应用程序 Windows DLL | 更新日期: 2023-09-27 18:04:57
我是C#中使用C++库以及一般C++编程的新手。我有一个从C++代码构建的DLL,我认为这是一个"托管"代码,因为DLL的名称是"TestManaged.dll"。我不是 100% 确定 dll/C++ 代码是托管/非托管的。
我想在我的C# windows forms application
代码中使用此 DLL 的类和方法。此 DLL 中有多个类。当我在Object Browser
中检查这些类和方法时,它们都有Public
标识符。
到目前为止,我已将此 DLL 添加到我的 C# 应用程序代码引用中。在我的问题中,我会谈论三个类:Product
、ReqStatus
、ProductData
。我可以为此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
类型的对象作为参数,并返回ReqStatus
,C++ 中的枚举类型。所以以下是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:是类Product
中的一个getConnected
方法,它接受一个字符数组(我不确定这一点(和一个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
getConnected
方法内部有一个对getProductData
方法的内部调用。
ReqStatus status = getProductData(data); //data is the same which was passed to the getConnected method
我的 C# 代码如下,我在两个方法调用中都遇到了错误:我在下面的代码片段中将错误放在同一行。这两种方法都是独立的。只是getProductData
是从C++代码中的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 );
}
}
对于错误2,我搜索了很多博客,发现可能的解决方案之一是使用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
更新:另外,我没有通过依赖沃克在此DLL中看到任何方法。现在,我已经有了C++的源代码。但我对C++编码相当陌生。如果需要对C++代码进行任何更改,请提供说明。
问候Rumit
enum ReqStatus
这是你最大的困扰。 这声明了本机枚举类型,它在托管代码中不可用,并使使用它的任何代码都无法访问。 必须使用 enum 类关键字声明它的托管版本,如下所示:
public enum class ReqStatus {
// etc...
}
代码周围的不安全块将使程序集无法验证安全协议,因此请警惕这一点。当我从 C# 调用C++(本机或非本机(的方法时,我不得不使用 PInvoke(平台调用(来调用它们。对于保护级别,我知道您说过C++中的所有内容都是公开的,但是如果您是C++新手,则可能犯了一个快速的语法错误。在 C# 中,所有方法都需要在存储说明符(公共、受保护等(之前,但在C++中,放置一个存储说明符后跟一个冒号,该存储和下一个声明的存储之间的所有内容都将是该存储类型。也许这是你的问题?
谢谢汉斯,指出问题。只是这样,我将枚举定义为"公共"。但是,我不确定您是错误地放置了"类"还是故意的,因为它给了我很多错误,因为它没有将其视为枚举,并且在我使用枚举的每个地方都要求一个对象。如果我在这里误解了什么,请告诉我。
所以,我只是通过公开枚举来工作。但是,我仍然无法找到如何将正确的值传递给 C# 中的 C++ 函数。(错误 1 在我的原始帖子中(。
当我调试C++代码时,它传递"0x0034E808"COM5"值(我假设它是一个内存位置和一个值?对于getConnected
方法的第一个参数。我试图通过实现不安全的方法传递这个值(在我的错误 1 的原始帖子中解释(,它传递"0x0277aab8"(再次似乎是一些内存地址(,但无法连接到它(获取串行端口超时错误(。与C++方法相比,我传递的值是否正确?
问候鲁米特