A call backwards from C++ to C# - c#

I'm using from C# a C++ library that wasn't quite developed for using from another languages, but it's difficult to change something now. I'm using [DllImport] calls, and nearly everything works fine.
But know I need to use a "backward" call from C++ to C#. So, in C# I need to subscribe to the C++ function. In C++ it is implemented like this:
INTF_API void __stdcall Intf_InstallHandler(Intf_MailHdlPtrType Hdl)
typedef void (STDCALL *Intf_MailHdlPtrType)(InstanceNoType instno,
const MailType* mail, rsuint16 mailsize);
(I've removed a few arguments from the method to make it simplier. They are two bytes - not important)
So in C# I have:
public delegate void MailEventHandler(byte Instance, MailType Mail, UInt16 MailLength);
MailHandlerDef defHandler = (f) =>
{
var structure =
(MailType)Marshal.PtrToStructure(f, typeof(MailType));
handler(structure);
};
Externs.Intf_InstallMailHandler(defHandler);
[DllImport(DLL_NAME, CallingConvention = CallingConvention.StdCall)]
public static extern void Intf_InstallMailHandler(byte Instance, [MarshalAs(UnmanagedType.FunctionPtr)] MailHandlerDef MailHandler, PrimitiveType Primitive);
We have different primitives (in C++ dll every method is a primitive, and every method is implemented as a call-and-wait method, or as an async method, where mailHandler is called on the end of the computation), and all primitives work, except one.
If this primitive is called, the NullRef exception is thrown, without any stacktrace. And I already lost my mind in trying to search what causing this. Intresting is that this doesn't work at our large application (even I tried to switch everyting off, and just call it at start up), but on my small test application it works.
Any help is appreciated.

you could use a .Net CLI C++ wrapper which would then call your standard C++ code.

Related

PinvokeStackImbalance occured. This exception is thrown but i have no idea what the error is?

The exception:
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'D:\UI_still_in_progress\user_interface\bin\Debug\WindowsFormsApplication1.vshost.exe'.
Basically my application has a background real time process in c++ which communicates with a micro-processor. Ive set up a c++ dll file which allows me to pass data from the c++ application and c# UI in real time.
My problem is that I have to create a finite state machine to make sure the physical device and c++ app are all doing what they should be based on whats going on in the UI. so my goal is to pass simple integers representing the states from c# to c++.
The real time data is passing from c++ to c# with no issues using the following implementation:
c++ .h file snippet:
extern "C" __declspec (dllexport) int grabx();
extern "C" __declspec (dllexport) void setFSMstate(int s);
C++ .cpp file snippet:
int grabx()
{
return x0;
}
void setFSMstate(int s)
{
state = s;
}
c# class
public class MyDllMethods {
[DllImport("dllTESTER.dll")]
public static extern int grabx();
[DllImport("dllTESTER.dll")]
public static extern void setFSMstate(int s);
}
c# method calls
xx = MyDllMethods.grabx();
MyDllMethods.setFSMstate(2);
The grabx() function works fine and i can read the x value from the device in real time. When my UI moves to a new screen i attempt to change the state in every application by passing a 2 into setFSMstate(). When this method is called the exception is thrown.
I am quite new to P/Invoke so if there is anything I missed please help out. I may have marshaled it wrong but im confident that type int is the same in c# and c++?
The problem you're running into is a calling convention mismatch. Calling conventions specify how parameters are passed to functions, and how their return values are passed back to the caller. Your C++ functions are being declared with an implicit calling convention of __cdecl, but P/Invoke's default calling convention is __stdcall.
To fix this, you just have to change your P/Invoke configuration:
[DllImport("dllTESTER.dll", CallingConvention = CallingConvention.Cdecl)]
(The reason you didn't have any problems with your first method is that it doesn't have any parameters—__cdecl and __stdcall pass parameters differently, but they both specify that integer return values are stored in the EAX register.)

How to PInvoke an Instance Method by disabling Name Mangling

Given the following c++ class in foo.dll
class a{
private:
int _answer;
public:
a(int answer) { _answer = answer; }
__declspec(dllexport) int GetAnswer() { return _answer; }
}
I would like the pInvoke GetAnswer from C#. To do that, I use the following method:
[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint= "something")]
public static extern int GetAnswer(IntPtr thisA);
And I pass in an IntPtr that points to an a (that I got from somewhere else, it's not important). CallingConvention = CallingConvention.ThisCall makes sure it's handled correctly
What's cool about this question is that I know I'm right so far because it's already working great! Using Depends.exe, I can see that "GetAnswer" is exported as ?GetAnswer#a##UAEHXZ (Or something close - the point being that it's been name mangled). When I plug the mangled name into the "something" for the EntryPoint everything works great! It took me about a day before it dawned on me to use Depends.exe, so I'm going to leave this here as a help to anybody who has a similar issue.
My REAL Question is: Is there any way to disable C++ name mangling on GetAnswer so that I don't need to put the mangled name in as my entry point. Having the mangled name in there seems like it could break, because my understanding of name mangling is that it can change if the compiler changes. Also it's a pain in the butt to use Depends.exe for every instance method that I want to pInvoke.
Edit: Forgot to add what I've tried:
I don't seem to be able to put extern "C" on the function declaration, although I can stick it on the definition. This doesn't seem to help though (which is obvious when you think about it)
The only other solution I can think of is a c-style function that wraps the instance method and takes an instance of an a as a parameter. Then, disable name mangling on that wrapper and pInvoke that. I'd rather stick with the solution that I already have, though. I already told my co-workers that pInvoke is great. I'm going to look like an idiot if I have to put special functions in our c++ library just to make pInvoke work.
You cannot disable mangling for a C++ class method, but you may well be able to export the function under a name of your choice using /EXPORT or a .def file.
However, your entire approach is brittle because you rely on an implementation detail, namely that this is passed as an implicit parameter. And what's more, exporting individual methods of a class is a recipe for pain.
The most sensible strategies for exposing a C++ class to .net languages are:
Create flat C wrapper functions and p/invoke those.
Create a C++/CLI mixed mode layer that publishes a managed class that wraps the native class.
Option 2 is preferable in my opinion.
You may be able to use the comment/linker #pragma to pass the /EXPORT switch to the linker which should allow you to rename the exported symbol:
#pragma comment(linker, "/EXPORT:GetAnswer=?GetAnswer#a##UAEHXZ")
Unfortunately, this does not resolve your need to look up the mangled name using depends or some other tool.
You do not have to disable the mangled name which actually contains lots of information of how the function itself is declared, it basically represents the whole signature of the function after the function name gets de-mangled. I understand you already found a word-around and the other answer has been marked as a correct answer. What I am writing below is how we can make it work as you desired.
[DllImport("foo.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "#OrdinalNumber")]
public static extern int GetAnswer(IntPtr thisA);
If you replace "#OrdinalNumber" with the real ordinal number of GetAnsweer, such as "#1", it will work as you desired.
You may just consider the EntryPoint property is the same as the function name we pass to GetProcAddress where you can either pass the function name or the ordinal number of the function.
Your approach to calling non-static function members of a C++ class is indeed correct and thiscall is used correctly and that is exactly thiscall calling convention comes in play in C# P/Invoke. The issue with this approach is that you will have to look into the DLL's PE information, Export Function Information and find out the ordinal number for each function you would like to call, if you have a big number of C++ functions to call, you may want to automate such a process.
From the Question Author: The solution I actually went with
I ended up going with a c-style function that wraps the instance method and takes an instance of an a as a parameter. That way, if the class ever does get inherited from, the right virtual method will get called.
I deliberately chose not to go with C++/CLI because it's just one more project to manage. If I needed to use all of the methods on a class, I would consider it, but I really only need this one method that serializes the class data.

Call C++ Dll in C#.net using dllImport

Please find the below Examples
void ExitLibrary(); // C++ function
I am able to covert to C# like below
[DllImport("VisualFOD.dll", CharSet = CharSet.Ansi)]
public static extern void ExitLibrary();
This method will be used to start the live capturing
bool StartLive(DShowLib::Grabber* f_Grabber, HDC f_hHdc, RECT f_WindowRect);
This method will be used to start the live capturing
[DllImport("TIS_UDSHL09_vc71.dll", CharSet = CharSet.Ansi)]
public static extern bool StartLive(IntPtr f_Grabber, IntPtr f_hHdc, Rectangle f_WindowRect);
I am not able to access the actual class DShowLib::Grabber as mentioned in the 2nd statement C++ function.
Do you have any idea how to declare and get the library class name?
This dll is not a COM/.Net dll to include as a reference to C# environment.
If I understand your question correctly, you won't be able to access the DShowLib::Grabber class directly in C# if it resides inside the DLL (and is accessed by a C++ header file).
Two solutions are available. Firstly, you can wrap the native DLL class in C++/CLI class, such that you can include the native C++ header files; Secondly, you can write your own DLL, where you can flatten the DLL class and P/Invoke your flatten methods.
By flattening I mean:
class C
{
void M(int i, float j);
}
The method M has to be called like:
__declspec(dllexport) BOOL __stdcall C_M(C * instance, int i, float j)
{
if (instance == nullptr)
return FALSE;
instance->M(i, j);
return TRUE;
}
However, please take into consideration comments for your question. If you can use ready-made wrapper for library you are interested in, you shall do so :)
There were many attempts to make C#/C++ interop easier, but by far managed C++ from Microsoft is probably the best (though it is not part of C++ standard).
Another promising option is CXXI from Mono,
http://tirania.org/blog/archive/2011/Dec-19.html
which provides a standard compliant approach.
It still needs some hacking (Google Summer of Code 2012 maybe), but it should finally support Visual C++ and Windows.
Yes. You can instantiate and access a C++ class object directly from your own C# code via PInvoke, but it is very complicated and involves a lot of work, please go here and read what that C++ PInvoke Interop SDK can do.
http://www.xinterop.com/index.php/2013/04/13/introduction-to-c-pinvoke-interop-sdk/
(It is a commercial software though. I am the author)

.net wrapper for native dll - how to minimize risk of run-time error?

I am developing a C# application. Since I have some algorithms for least-squares fit in C/C++ that would be too cumbersome too translate, I have made the C++ code into a dll and then created a wrapper in C#.
In the C# code, I have defined a struct that is passed to the unmanaged C++ code as a pointer. The struct contains the initial guesstimates for the fitting functions, and it is also used to return the results of the fit.
It appears to me that you must define the struct in both the managed and the unmanaged code. However, someone using my source code in in the future might decide to change the fields of the struct in the C# application, without understanding that they also have to change the struct in the native code. This will result in a run-time error at best (and produce erroneous results at worse), but there will be no error message telling the developer / end user what is wrong.
From my understanding, it impossible to create a test in the unmanaged C++ DLL that checks if the struct contains the correct fields, but is it posible to have the DLL returning a struct of the correct format to the C# wrapper?
Otherwise, what ways are there to reduce the risk that some careless programmer in the future causes run-time errors that are hard to detect?
Sample code:
//C++
struct InputOutputStruct {
double a,b,c;
}
extern "C" __declspec(dllexport) void DoSomethingToStruct(InputOutputStruct* s)
{
// ... algorithm
}
//C#
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct InputOutputStruct {
public double a,b,c;
}
[DllImport("CpluplusDll.dll")]
public static unsafe extern bool DoSomethingToStruct(InputOutputStruct* s);
class CSharpWrapper {
static void Main(string[] args)
{
InputOutputStruct s = new InputOutputStruct();
unsafe {
InputOutpustruct* sPtr = &s;
DoSomethingToStruct(sPtr);
s = *sPtr;
}
}
}
It appears to me that you must define the struct in both the managed
and the unmanaged code.
Not true. This is what C++/CLI was invented for- facilitate much easier interoperation with C++ and .NET.
but is it posible to have the DLL returning a struct of the correct format to the C# wrapper?
I don't think so, because you always need to define the structs on the C# side.
Here are a solution which may work ( never tested ):
Give each struct which is shared a unique identifier on both sides ( GUID, Macros )
Create a reflection for C++ which contains informations about the the types which are used on C# and C++ side. This could be done by using macros.
Compare the C++ structs and the C# structs on startup by using the GUIDs, reflection and macros. You can also use sizeof to compare sizes first.
That could be a lot of work
When working on C++ side you still can make a lot of things wrong when you not know about the macros

Expose Borland C++ methods to C#

I have following method in my Borland C++ code,
static bool UploadBitstream(void)
{
//Some code Implementation
}
And I'm trying to convert it to DLL and access it in C#.
What are the steps I need to follow to Convert the code DLL
and then use it in C# ??
First, you have to make sure that the methods are defined extern. Then you need to declare the method stdcall or pascal calling convention, and mark them dllexport. See code listing below (this is ancient memory for me, so pardon if I am a bit off on modern Borland C++ compilers).
// code.h
extern "C" {
#define FUNCTION __declspec(dllexport)
FUNCTION int __stdcall SomeFunction(int Value);
In the main
#include "code.h"
FUNCTION int __stdcall SomeFunction(int timesThree)
{
return timesThree * 3;
}
Once you've compiled your DLL all you should need to do in .NET to get access to it is use the DLLImport property.
public class stuff
{
[DLLImport("somedll.dll")]
public static extern void UploadBitstream();
}
If you need pointers or anything like that it gets more complicated but for void functions it's that simple.
It should be noted that once you invoke that function the dll will be loaded by your program and won't be released until your program is closed. You can dynamically load dlls but that is much more complicated. I can explain it here if you have a need.
Watch your terminology.
In your example UploadBitstream is function not a method.
If it is indeed a method in a class then it is very difficult to use classes from Borland compiled DLLs.
If your code is actually C not C++ you should be able to create a compatible DLL
for your simple C style functions with C++ Builder.
See the following SO question:
Use a dll from a c++ program. (borland c++ builder and in general)
where I list various compiler settings which will also apply to creating compatible DLLs.

Categories

Resources