我不熟悉在 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++ 代码,如下所示。在这种情况下,在 C# 中ProductData
显示为类Object Browser
,因为它实际上是 C++ 代码中的结构。我不确定这对回答我的问题是否重要(最后)。
以下是定义ProductData
struct - ProductData.h
file 的 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:是类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++ 代码进行任何更改,请给出指示。
问候, 鲁米特