Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 471
Pete Baughman Avatar asked Jul 10 '13 19:07

Pete Baughman


2 Answers

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:

  1. Create flat C wrapper functions and p/invoke those.
  2. Create a C++/CLI mixed mode layer that publishes a managed class that wraps the native class.

Option 2 is preferable in my opinion.

like image 174
David Heffernan Avatar answered Oct 04 '22 06:10

David Heffernan


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.

like image 28
Michael Goldshteyn Avatar answered Oct 04 '22 05:10

Michael Goldshteyn