Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top