I am currently using PInvoke to call some unmanaged functions from C++ in C#; specifically from PhysX 3.3.3. I am relatively new to PInvoke so I started with some simple methods. I can easily call functions that take no parameters but am having trouble calling any that do.
Starting simple, I used a function that passed in a boolean and discovered that booleans are non-blittable types so they must be marshaled. However, adding the boolean marshaling to the PInvoke signature still did not work.
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getReportAllocationNames#Foundation#shdfnd#physx##UEBA_NXZ")]
public static extern bool GetAllocationNames();
[DllImport("PhysX3CommonCHECKED_x64.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?setReportAllocationNames#Foundation#shdfnd#physx##UEAAX_N#Z")]
public static extern void SetAllocationNames([MarshalAs(UnmanagedType.U1)]bool name);
When I call SetAllocationNames(true), I get an AccessViolationException. I have also tried using other member names for the UnmanagedType enumeration (e.g. U1, Bool) but to no avail.
I am loading the DLLs prior to calling the functions, I am using the correct mangled name as the entry point, and I am calling all parameters associated with this function (just one in this case). Is there something else I'm missing?
Unfortunately, it is mostly impossible to share C++ libraries with other C++ applications if they were compiled with a different compiler (and even worse, different versions of the same compiler) , yet alone using PInvoke.
Secondly, you're not even close at tackling this problem. C++'s calling convention (in x86) for methods (functions that belong to a class) is thiscall, which means that this (the class the method is called upon) is passed via the ecx or rcx register. cdecl doesn't pass one. Secondly, you didn't even define the appropriate classes...
What you should do is to write a C++ wrapper
Write functions, not methods (i.e - not bound to any class or struct), that do whatever you need to be done, and make sure that you know their calling convention (make it something conventional, like cdecl or fastcall). This way you can write C/C++ code to do the work for you, and write C# with PInvoke.
Okay, I think I understand now. After further research, it does seem that inherited functions are problematic for PInvoke. Many sources recommend flattening the C++ code to a C style interface. I will have to use a C++/CLI project instead. Thanks!
Related
I have an unmanaged DLL that exports C style non-member functions for creating (say CreateObject) and destroying objects (DestroyObject). CreateObject returns a C++ class as a void*, which in the unmanaged code is cast to a known interface (defined only in a header file) and worked with. Is there a way to call methods on the IntPtr that is returned to me by CreateObject?
Dumpbin /EXPORT doesn't show me any methods of the C++ class, just the exported C functions (mentioned above).
I would like to avoid having to write C++ CLI code or a purely unmanaged DLL that simply exposes methods on this class as function wrappers if possible
This is Windows/MSVC only, so answers that restrict compatibility to Windows/MSVC are fine.
NOTE: I'm talking about invoking C++ methods on a void*/IntPtr returned by a C function - not P/Invoking the C functions.
Thanks!
If you are ruling out C++/CLI, and only have an IntPtr containing the address of the instance then you have few options remaining.
As I see it you are left with p/invoke. In order to call a method you'll need to export it from your unmanaged code. You'll also need to be careful about the calling convention. Commonly it will be __thiscall. When you write the p/invoke, you must explicitly add the this pointer as the first parameter.
This is fine so far as it goes. But you'll not be able to export virtual methods this way. You cannot call them using p/invoke.
Frankly though the cleanest and simplest way to do this interop is with our old friend, tried and tested COM. This very scenario is just what it was designed for. C++ classes are not designed for interop across compiler/language boundaries. That's what COM is for.
I have a vendor's DLL that is meant to be called from C++, but I need to call it from C#.
Using an app called PE Explorer I can see the list of exported methods in the DLL (call it Protocol.dll for now) and even get an 'Undecorated C++ Function' signature like this:
public: unsigned int __thiscall Myco::Protocol::tMultiThingClient::GetThings(char (* const)[16],unsigned int)
How do I use something like that in C#? I know I use DllImport, I just don't know how to go from the signature above to a proper DllImport signature.
Total WAG:
[DllImport("Protocol.dll", EntryPoint="GetThings")]
public static extern void GetThings(ref string[], uint);
Is that even close? Is there a reference somewhere that translates between C++ declarations like char (* const)[16] and their C# equivalents?
You need to create a seperate project containing mixed assembly using C++ CLI. For this, you need to enable the CLR compiler switch in your project properties. Since, the project allows mixed assembly, you can call the C++ function, and also create a C# interface for your main program to call.
So, your main program will call the interface you implement inside your C++ CLI project, which will in turn call the C++ funtion inside the DLL.
Please beware of Marshalling and Thunking while you do this, if it applies to your system considerations.
I am writing C# code that interfaces to a legacy (Feb 2012) C program, using DllImport. It works fine, but I need to call more than 30 different functions, turning my normally impeccable, exquisite code into something of near-elephantine proportions. Surely there must be a way around this? [Warning: those with weak stomachs may want to avert their eyes from what follows]:
[DllImport("C:\\Users\\mitt\\Documents\\Visual Studio 2010\\Projects\\mrSolution\\mr\\x64\\Debug\\mrDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern bool mrEngine_initialize( [In, Out, MarshalAs(UnmanagedType.LPStruct)] PLOT_SPEC PlotSpec);
[DllImport("C:\\Users\\mitt\\Documents\\Visual Studio 2010\\Projects\\mrSolution\\mr\\x64\\Debug\\mrDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern bool mrEngine_getDataPoint( [In, Out, MarshalAs(UnmanagedType.LPStruct)] PLOT_SPEC PlotSpec);
This is fairly inevitable with a C style api. The Windows api being a prime example of one with thousands of functions. Tying them together with handles. With the handle being the C style equivalent of this, the object reference for a class object.
The next leg up is a COM interface, it allows building an object model. Very common in Windows apis, looks like you lost out on that one.
This however doesn't stop you from creating your own object model, using C# classes whose methods and properties map in a logical way to the underlying C style api. The fugly code that implements your class members and makes the pinvoke calls can be hidden in a #region that you hopefully never have to look at again.
There is more than one benefit to doing it this way. Thinking about the object model mapping really helps you to understand the underlying api. And gives you plenty of unit test extension points. And makes you feel really good about creating order out of chaos.
Try to just reference the dll in your project. Sometimes it just works and Visual Studio does all the plumbing for you. If Visual Studio complains for some reason, try to use the tool TblImp.exe. It creates a wrapper that you can reference in your project.
DllImport has a restriction that makes it applicable only to methods. Although it can get ugly, it is quite simple and truly reflects it's intent.
There are two things that come to my mind right now:
Use a partial class and split your imports into multiple files. It will make each file smaller and won't hurt your eyes;
Use T4 to generate the class that contains the imports and forget about it's existence.
Let's assume I have an unmanaged class Test:
class Test
{
public:
int SomeMethod(int a, bool b);
};
To create a new instance of Test, I'd:
Test *test = new Test();
My goal is to embed Mono so that managed code could call unmanaged methods (like Test::SomeMethod) in a specific object. I represent that object by passing a pointer of that object to the managed method, like that:
void *args[1];
args[0] = &test;
mono_runtime_invoke(init, NULL, args, NULL);
Here is how the managed method that is being invoked looks like:
public static void Init(IntPtr test)
{
}
From here, how can I call Test.SomeMethod?
I thought about using emitting the CALLI instruction, using System.Reflection.Emit, but how can I refer to the object that the pointer test (the first parameter of Init) is referring to?
I do not want to use DllImport.
You might be interested in CXXI. It creates a managed assembly based on your C++ headers and allows you to work with C++ objects as if they were normal managed objects.
As far as I understand it, it's not finished yet and works only with C++ code compiled by GCC.
Can't be done (Or at least shouldn't be done).
You're trying to directly mix two completely different execution environments - the reason why DLLImport exists is to allow the compiler to solve this problem.
In .NET, you can create mixed-mode applications (C++/CLI) which allow managed code and unmanaged code to co-exist in the same binary (and call each other), but since you're talking about mono, I'm assuming that option is out.
Managed environments like .NET have strict type rules, garbage collection and other features that simply don't work with unmanaged code and data.
You can use an internal call, if you don't want to use DllImport.
See https://github.com/mono/mono/blob/master/samples/embed/teste.c the mono_add_internal_call() invocation and the C# code in the test.cs file.
This works mostly like DllImport, except there is no marshalling done for you (a string object in C# code will appear as a MonoString* in the C code, not as a char*, for example).
In any case, note that both the function you could access with DllImport and the function pointer registered with mono_add_internal_call() must be C functions, not C++ member methods.
In C# the extern modifier is used to declare a method that is implemented externally. Usually it is used with DllImport attribute to call some function in unmanaged code.
I wonder if there is a way to provide custom implementation of extern method?
To understand better the problem consider the following use case. I have a set of functions implemented in unmanaged code and I'd like to supply pointers to these function in run-time (during the loading of assembly).
The same thing DllImport attribute does, but I'd like to provide pointers by myself.
This is possible although you would need to PInvoke several things (LoadLibrary and GetProcAddress - see links below)... it is called "late binding native code"...
Some relevant links with source:
http://blogs.msdn.com/b/junfeng/archive/2004/07/14/181932.aspx
http://www.codeproject.com/KB/cs/dyninvok.aspx
http://pinvoke.net/default.aspx/kernel32/GetPRocAddress.html
http://www.pinvoke.net/default.aspx/kernel32.loadlibrary
You would need to use LoadLibrary and GetProcAddress