问题
I am new to using C++ libraries in C# and also to the C++ programming in general. I have a DLL built from a C++ code which I believe is a 'managed' code as the name of the DLL is "TestManaged.dll". I am not 100% sure if the dll/C++ code is managed/unmanaged.
I want to use classes and methods of this DLL in my C# windows forms application
code. There are multiple classes in this DLL. When I chekced these classes and methods inside those classes in Object Browser
, all of them have Public
identifier.
So far, I have added this DLL to my references of C# application code. There are three classes I would talk about in my question: Product
, ReqStatus
, ProductData
. I could create an object(s) for various classes of this DLL as follows.
Product testCall = new ProductClass();
There is another class called ProductData
in this DLL and I could get the C++ code for this class which is as follows. In this case, ProductData
is shown as class in Object Browser
in C# where as it is actually a struct in C++ code. I am not sure if this is important to answer my question (at the end).
Following is a C++ code that defines ProductData
struct - ProductData.h
file.
#ifdef WIN32_MANAGED
public ref struct ProductData
#else
struct ProductData
#endif
{
UINT32 ProductId; //!< Product ID
UINT32 PRoductRev; //!< Build Revision
};
Following is a C++ code that defines ReqStatus
enum - ReqStatus.h
file. I have created the same enum in my C# code with no identifier specified.
enum ReqStatus
{
SUCCESS, //!< Method was successful
//Connection errors
NOT_CONNECTED, //!< Connection not open
CONN_TIMEOUT, //!< Connection timed out commuincating with device
};
Now, there are two methods I want to call and have problems with both:
Method 1: is a getProductData
method inside Product
class which accepts object of ProductData
type as a parameter and returns the ReqStatus
which is an enum type in C++. So following is the declaration of the gerProductData
method (as seen in the Object Browser
):
public ReqStatus getProductData(ProductData data)
The same method's C++ delcaration is: (The actual method is too long and hence just giving the declaration): This method is inside Prodcut.cpp
file
ReqStatus Product::getProductData(ProductData PLATFORM_PTR data)
PLATFORM_PTR is defined as below in Platform.h
#ifdef WIN32_MANAGED
#define PLATFORM_PTR ^
#else
#define PLATFORM_PTR *
#endif
Method 2: is a getConnected
method inside Product
class which accepts a character array (I am not sure of this) and an object of ProductData
type as a parameter and returns the ReqStatus
which is an enum type in C++. So following is the declaration of the getConnected
method (as seen in the Object Browser
):
public ReqStatus getConnected(sbyte* someChar, ProductData data)
The same method's C++ delcaration is: (The actual method is too long and hence just giving the declaration): This method is inside Prodcut.cpp
file
ReqStatus Product::getConnected(const char *someChar, ProductData PLATFORM_PTR data)
C++ code calls the methods as follows:
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
There is an internal call to getProductData
method inside the getConnected
method.
ReqStatus status = getProductData(data); //data is the same which was passed to the getConnected method
MY C# code is as follows and I got errors at both method calls: I have put errors on the same line in the below code snippet. Both methods are independent. Its just that the getProductData
is called from getConnected
method in C++ code. I wanted to check if I can call both individually.
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
For Error 1, I tried solutions from various articles on StackOverflow and other forums but, could not solve it. Just for a reference, I tried to change the "SomePortCOM" as follows but it din't work.
UPDATE: This code works fine now and I don't see Error 1(Invalid arguments). Now, I only need to get rid of the Error 2 (Protection level error). Kindly provide any suggestions. Thank you.
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 );
}
}
For Error2, I searched so many blogs and found that one of the possible solution could be the use of DLLImport, I tried that as well and I have following issue:
C# declaration of DLLImport:
[DllImport("TestManaged.dll",EntryPoint="getConnected")]
public static extern ReqStatus getConnected(String SerialPort, ref ProductData pData);
I am calling this function as below from my C# code:
ProductData pData = new ProductData();
String str = "COM7";
ReqStatus status1 = getConnected(str, ref pData);
However, I am getting Entry point not found
error. I tried to run the dumpbin function to get the list of functions exported by this DLL. But, I do not see any functions. Rather just a random output as below.
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
UPDATE: Also, I do not see any methods in this DLL via Dependency Walker. Now, I have got the source code for C++. But I am fairly new to C++ coding. In case any change is required to C++ code, kindly give the directions.
Regards, Rumit
回答1:
enum ReqStatus
That's your biggest hang-up. That declares a native enum type, it is not usable in managed code and makes any code that uses it inaccessible. You must declare the managed version of it with the enum class keyword, like this:
public enum class ReqStatus {
// etc...
}
回答2:
The unsafe block around your code will make it so your assembly cannot be verified for security protocols, so be wary of that. When I've called methods from C++ (native or not) from C# I've had to use PInvoke (Platform Invoke) to call them. For a protection level, I know you said everything is public in the C++, but if you're new to C++ you may have made a quick syntax mistake. In C#, all methods need to be preceded by a storage specifier (public, protected, etc...) but in C++ you place a storage specifier followed by a colon and everything between THAT storage and the next declared storage will be of that storage type. Maybe this is your issue?
回答3:
Thank you Hans, for the pointing out the problem. Just that, I made the enum definition as 'public'. But, I'm not sure if you put the 'class' by mistake or was it intentional as it was giving me so many errors as it wasn't taking it as an enum and was asking for an object at every place I used enum. Let me know if I misunderstood anything here.
So, I got it worked just by making the enum public. However, I am still not able to find how to pass the correct values to that the C++ function from C#. (Error1 in my original post).
When I debuged the C++ code, it passes the "0x0034E808 "COM5" value (I assume it's a memory location and a value?) for the first parameter of the getConnected
method. I tried to pass this value by implementing the unsafe method (explained in my original post for Error 1), it passes "0x0277aab8" (again seems some memory address), but could not get connected to it (Getting serial port timeout errors). Am I passing the value incorrectly compared to C++ method?
Regards, Rumit
来源:https://stackoverflow.com/questions/15508310/using-c-dll-in-c-sharp-windows-applicationgetting-error-entry-point-not-foun