1

I can call C++ wrapper class from C# via

[DllImport("SomeDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void M();

Where in the C++ code I have

extern "C" { __declspec(dllexport) BSTR GroupTerm(); }
void M() { /* Do Stuff */ }

This works great, however for a number of reasons, I want to include the method M in a class

class SomeClass {
public: 
    void M();
}

I have tried doing

class SomeClass {
public:
   void __declspec(dllexport) M();
}

where

void __declspec(dllexport) SomeClass::M() { /* Do Stuff */ }

But the C# code (using the C# code for import declared above) cannot find the entry point and throws an exception. My question is then, how can I export this method M() [which is a public member of SomeClass for use with interop/pinvoke from C#?

Thanks for your time.

MoonKnight
  • 23,214
  • 40
  • 145
  • 277
  • 1
    How would you export only a single non-static class method? What instance would you call it on? – nvoigt Apr 02 '14 at 16:44
  • Good point. Okay lets say I made the method `static`, could this be done then? If so how? – MoonKnight Apr 02 '14 at 16:49
  • Just to mention, static C++ methods are kindof a pain to export due to name mangling. See http://forums.codeguru.com/showthread.php?353526-DLL-export-static-function – IdeaHat Apr 02 '14 at 17:05

3 Answers3

4

Well there is a few ways, all with different merrits.

One of the more simple is to make a C-wrapper for your C++ class (i'm too lazy to put in the decorations, you should do that yourself).

class SomeClass {
public: 
  void M();
};

void* MakeSomeClass() {return new SomeClass();}
void DestroySomeClassHandle(void* handle) { delete (SomeClass*)handle;}
void M(void* handle) { ((SomeClass*)handle)->M();}

Then you import the C functions as you normally would.

The upside to this is you don't have to do anything you aren't currently familiar with. Many more things (Matlab, Python, ect) have things similar to PInvoke, so this makes your code much more cross-language usable.

The downside is this is super error prone, and you throw away alot of your type safety.

The better way (imho) is to make a C++/CLI wrapper for the class

public ref class ManageSomeClass
{
public:
  ManageSomeClass() {myclass_ = new SomeClass();}
  !ManageSomeClass() { if (myclass) {delete myclass; myclass_ = NULL;} }
  ~ManageSomeClass() { this->!ManageSomeClass(); }
  void M() { myclass_->M();}
private:
  SomeClass* myclass_;
};

I used SomeClass as a pointer to show the destructor-finalizer, but it doesn't need to be a pointer. It could be a full instance. The big thing is that this will be compiled into a .NET class (in a dll) and you can import it into your C# code. Then the call is:

//c# code
ManageSomeClass msc = new ManageSomeClass();
msc.M();

Upside is the flexibility to go from managed to unmanaged like that. The downside is that you are suddenly maintaining another interface. If you have inheritence/polymorphism, your wrappers have to mirror that structure. This is also a nightmare to maintain.

Edit: Another downside is you have to learn C++/CLI, which is (kindof) and extension of C++ and also (kindof) a completely different language.

The final way is through COM interfaces. http://msdn.microsoft.com/en-us/library/aa645736%28v=vs.71%29.aspx. You can use the same COM import calls you use in C++ in C# (with some minor differences) to instantiate and call COM classes. But you need to learn COM (which I've never done) and then implement your class in a COM complaint way. But then you have a COM interface, which can be imported all over Windows.

IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • Top top answer! Thanks very much. The issue is I am new to this stuff... I am writing this C++ class to somehow wrap an existing C library. I has occurred to me from your answer that I could just be doing this directly with the C code (if it was accessible which I will find out). This code is from an existing COM library and the reason why I am doing this is speed; the COM library had to be called from C# using late-binding and made it slow. I might look at creating a managed wrapper class instead of using pinvoke, but like you say it is another thing to maintain. Again, thanks for your time. – MoonKnight Apr 02 '14 at 17:15
1

Assuming the method is static you have a couple of choices:

  1. Use a tool like Dependency Walker to find out the name under which the function is imported. Use the EntryPoint parameter of DllImport to locate it.
  2. Export the function with a .def file. Then you have total control over the exported name.
  3. Wrap the method in a non-member function and export that.

Frankly, option 3 is the one I would select.

When you get around to member functions you'll need to export functions that accept an instance pointer as their first parameter. And you'll likely have to export functions that instantiate objects.

That said, and responding to your comments, other likely better solutions to your problem are:

  1. Early bound COM, or
  2. A C++/CLI wrapper.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 3. is good, but this whole thing is one ugly mess. We have manuals that were for the old COM library. This COM library was for consumption with VB6 (yes, that old). Now, I have been told to upgrade the COM library for use with .NET. The thing is, if I can use the same method names (which is why I wanted to encapsulate the method in a class) I will avoid having to rewrite the manual ect. Having never worked with C/COM, I am finding this a bit overwhelming in terms of what I _don't_ know. I have been reading all day and think I have a much better understanding thanks to you and this site. – MoonKnight Apr 02 '14 at 17:15
  • If you have a COM library why are you changing? COM works well. – David Heffernan Apr 02 '14 at 17:17
  • It is massively slow due to the requirement to use late-binding. The old code is a grouper, and is very fast. When I run the grouper library via COM using C# (using `dynamic`) the code performance is drastically reduced. There is a number of reasons for this and some great existing answers on why etc. This is the reason for all this upheaval. I have been asked to rewrite the entire thing, but before I can we must support what we have for one more year, for this we must be able to call the grouper from C#... – MoonKnight Apr 02 '14 at 17:21
  • COM is a very efficient way to expose objects to C#. Why are you giving up on it? – David Heffernan Apr 02 '14 at 17:24
  • I have said that it is very slow indeed... That's why. It is great if the methods that you are calling do alot of work per call. But in our case the COM method being called groups one record at a time which can be done in a few CPU ticks (very quick); we want to be able to provide users with the ability to batch group 1,000s of records, but we see that when calling the group function from C# via COM there is a massive performance hit due to the late-binding requirement. – MoonKnight Apr 02 '14 at 17:50
  • You won't find that p/invoke is faster I don't think. – David Heffernan Apr 02 '14 at 17:51
  • Also, why are you using late binding? – David Heffernan Apr 02 '14 at 17:55
  • Please tell me otherwise... Please. The whole reason I am doing this is due to performance. Surely the pinvoke method will be faster, if you look at what is required by the DLR behind the scenes, inorder to late-bind using dynamic (http://stackoverflow.com/a/7480977/626442) it _must_ be faster... – MoonKnight Apr 02 '14 at 17:56
  • How else can I invoke the COM library, the original author of the COM server only permitted the consumer to use it late-bound. The equivalent of [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] in .NET. I found this out attempting to include a reference to the COM library in my C# code. All I have access to was an empty interface... Are you saying I should attempt to modify the COM library to allow me to invoke the methods without late-binding? Thinking about this, it seems like it could be a better approach; the only thing is I know nothing about COM! – MoonKnight Apr 02 '14 at 18:01
  • That's exactly what I am saying. It will be easy to modify the code to support early binding. I do believe it's the right solution. – David Heffernan Apr 02 '14 at 18:11
  • Thanks David. Your help is most appreciated. I work on my own, so I find it difficult sometime with no one to ask for advice. I really appreciate your time here... – MoonKnight Apr 02 '14 at 18:21
  • I am trying to award you a bounty for the help, but I can't seem to do this yet... I am going to ask another question shortly and wondered if you can take a look. I am struggling to find anything about making my existing COM library interface include methods. Indeed any material about creating COM libraries at all. I spoke to author this morning and he said he wrote the code 17 years ago and with the help of Visual C++ 6 which had templates for creating COM libraries. Is it worth showing the existing COM and asking how to make methods visible or is there any links you know of that I can read? – MoonKnight Apr 03 '14 at 13:15
  • 1
    I think I'd start with Don Box's Essential COM – David Heffernan Apr 03 '14 at 13:23
1

Another method (apart from what @MadScienceDreams and @DavidHeffernan said) is to make your C++ code into a Windows Runtime DLL and then it can be used in your C# code. See here for the details and sample: Creating Windows Runtime Components in C++

Excerpt from the link:

article shows how to use C++ to create a Windows Runtime component, which is a DLL that's callable from a Windows Store app that's built by using JavaScript—or C#, Visual Basic, or C++

...

In general, when you code your C++ component, use the regular C++ library and built-in types, except at the abstract binary interface (ABI) boundary where you are passing data to and from code in another .winmd package. There, use Windows Runtime types and the special syntax that Visual C++ supports for creating and manipulating those types. In addition, in your Visual C++ code, use types such as delegate and event to implement events that can be fired from your component and handled in JavaScript, Visual Basic, or C#.

Here is the sample code for "Creating Windows Runtime Components in C++".

yasouser
  • 5,113
  • 2
  • 27
  • 41
  • This assumes that the program will only ever be run under WinRT which is a very radical assumption. – David Heffernan Apr 02 '14 at 18:24
  • Not exclusive to WinRT. You can make desktop applications consume WinRT components. See here: http://software.intel.com/en-us/articles/using-winrt-apis-from-desktop-applications One constraint is that you can do this only on Windows 8 and above. – yasouser Apr 02 '14 at 20:27
  • Wouldn't it just be easier to use C++/CLI? And what if the user wants to run on Windows 7. – David Heffernan Apr 02 '14 at 20:29
  • Yes. But I was simply giving an alternate to what you have mentioned :) – yasouser Apr 02 '14 at 20:30