14

I've got a native C++ DLL that I would like to have a C++/CLI wrapper layer for. From what I understood, if you simple added a C++/CLI class to the project, VS would compile as mixed mode, but I was apparently wrong as VS doesn't seem to be even touching the managed code.

So, given a pre-existing native code-base what exactly, step-by-step, do you need to do to create a mixed mode DLL, so that I can can link into that code from any .NET language?

*I need to do this because my native code uses C++ classes that I cannot P/Invoke into.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Adam Haile
  • 30,705
  • 58
  • 191
  • 286
  • Do you want to compile the existing C++ source into a new DLL, or do you want to make a C++/CLI classlib which uses the older native code DLL? – kmontgom Apr 22 '10 at 13:47
  • 1
    @kmontgom - Having a single DLL would be nice, but honestly I would rather do whatever is best practice. – Adam Haile Apr 22 '10 at 13:48

6 Answers6

19

Well, no, it doesn't get to be mix-mode until you tell the C++/CLI compiler that your legacy DLL was written in unmanaged code. Which should have been noticeable, you should have gotten linker errors from the unmanaged DLL exports. You need to use #pragma managed:

#pragma managed(push, off)
#include "oldskool.h"
#pragma comment(lib, "oldskool.lib")
#pragma managed(pop)

using namespace System;

public ref class Wrapper {
private:
    COldSkool* pUnmanaged;
public:
    Wrapper() { pUnmanaged = new COldSkool; }
    ~Wrapper() { delete pUnmanaged; pUnmanaged = 0; }
    !Wrapper() { delete pUnmanaged; }
    void sampleMethod() { 
        if (!pUnmanaged) throw gcnew ObjectDisposedException("Wrapper");
        pUnmanaged->sampleMethod(); 
    }
};
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I assume this is for if you were creating a new DLL and linking to the completely native DLL? – Adam Haile Apr 22 '10 at 14:14
  • 1
    Whether that pulls in a native DLL depends on whether oldskool.lib is an import library or a static library. – Ben Voigt Apr 24 '10 at 05:51
  • @AdamHaile: As hinted to by Ben Voigt, the pattern presented in this answer can be used to generate truly mixed-mode assemblies, that contain both native (unmanaged) object code, as well as CLR-visible, managed types. The `ref class Wrapper` forwards calls to the unmanaged implementation, that can reside in a separate module or get compiled into the same module. – IInspectable Oct 03 '16 at 15:53
  • @BenVoigt Is this approach a good one if one has a 3rd party static C++ library and want to create a set of DLL classes on top of it for C# to consume? – Mateusz Grzejek Mar 28 '18 at 13:32
  • It just doesn't matter. And it is not like you have a choice, that static library doesn't magically turn into a DLL. – Hans Passant Mar 28 '18 at 13:39
  • @MateuszGrzejek: Yes, a set of C++/CLI wrappers is the way to give C# access to a C++ library. But don't use Hans's example as a template... write the smart pointer (`new`/`delete`) *once* and reuse it via composition. – Ben Voigt Mar 28 '18 at 15:04
6

A good option to prevent /clr from affecting your existing code is to compile all the existing code into a native static library and then include that static library at the link step of your C++/CLI dll.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

Begin a new C++/CLI project and then move your native classes to it.

Dan Byström
  • 9,067
  • 5
  • 38
  • 68
1

Instead of Turning on the "Common Language RunTime Support" at the Project Level, it's possible to enable it on a file-by-file basis only by looking at the Properties of the File, and going to C/C++ | General | Common Language Support.

This might make it easier to have your native and C++/CLI code in the same project, rather than creating a separate C++/CLI DLL just containing the wrapper, or having to use lots of managed/unmanaged pragmas.

So just do that on the C++/CLI .NET wrapper class you want to write.

Colin Smith
  • 12,375
  • 4
  • 39
  • 47
0

If you has a source code of the DLL with native C++, you can use managed C++ in the mixed mode. Microsoft has for some time a reference project of migration of some well known DirectX game to .NET. One used managed C++ in the mixed mode. A part of code was rewritten as managed code. A part was shortly changed to be compiled as C++ in the mixed mode and a part was compiled as assembly code (because of performance reason), but used also directly inside of managed code as unsafe code. Such kind of migration follow as a result to really very good performance in the end application. In this way you don't spend time for marshaling between native and managed code. Marshaling between safe and unsafe managed code is much quickly. Probably you should also choose this way?

Another way calling native code from DLL inside of manged .NET code is well known. Every C++ function has undecorated names (use http://www.dependencywalker.com/ to see there). If your C++ DLL export classes and not C-like functions, this DLL is bad designed. Good designed DLL either exports C-like functions or export COM-interfaces. If you have such "bad" DLL and don't want spend time to write a COM, you can easy write one more DLL which will be play a stub role. This DLL imports all C++ classes (see http://msdn.microsoft.com/en-us/library/81h27t8c.aspx, Exporting a C++ class from a DLL and http://www.codeproject.com/KB/cpp/howto_export_cpp_classes.aspx for example) from "bad" DLL and export C-like function. This way is also OK.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Sorry, this is **so** uninformed, that I had to down-vote on it. *"Every C++ function has undecorated names"* - uhm... no. The remainder is just so utterly useless that I cannot find a good explanation for the up-vote this proposed answer received. Except for pointing out, that COM is **one** valid interop strategy, everything else is either misleading or rightout wrong. I'll suggest deletion (seriously). – IInspectable Oct 03 '16 at 12:09
  • @IInspectable: Look at the date of the answer first of all. It's unclear for me, which scenario you have and what you are looking for? In my opinion the origin of the problem is good, language and compiler independent, exporting of objects and methods from C++ in for of DLL. COM provides very good solution of the problem. Good design of mix C++/CLI creation in my options will consist from C++ development in form of COM dlls and the usage of the DLLs in C# or development of COM in C# and the usage the C# DLL in C++. – Oleg Oct 03 '16 at 12:24
  • Like your answer, this comment was completely incomprehensible. At any rate, with respect to managed/unmanaged interop, **nothing** has changed in between you posting this proposed answer and today. There's absolutely no need to introduce COM to wrap unmanaged functionality in a `ref class` (see the [highest voted answer](http://stackoverflow.com/a/2691448/1889329)). It appears that you don't know or understand C++/CLI. In other words: If all you have is a hammer, eventually every problem starts to look like a nail. Sorry, this isn't a useful contribution. – IInspectable Oct 03 '16 at 12:27
  • @IInspectable: I see no sense in the discussion. Probably you don't understand COM deep enough and the binary representation of DLL like exports tables, common problems of memory management inside of DLLs and so on. If you don't like my answer, don't like COM or something else then it's your problem. You can upvote or downvote any question or answer, but I see no sense in the later discussion. – Oleg Oct 03 '16 at 12:46
  • 1
    It's funny, that you assume someone with the screen name *IInspectable* would be unfamiliar with COM. At any rate, using COM is tedious. You'd have to author an IDL file, implement a COM object, either register it, or implement registration-free COM. Lots of work, for no apparent benefit. Using C++/CLI to write an interop-assembly is so much easier. Your other .NET code can immediately consume the mixed mode assembly. It really sounds, like you do not know C++/CLI (you are talking about *"managed C++"*, which has been dead for roughly a decade when you answered the question). – IInspectable Oct 03 '16 at 15:24
  • @IInspectable: I repeat that I see no sense in the discussion. Your previous comments sounds like the words of an braggart, and not show that your *understand* COM. You can start with understanding the problem of exporting C++ classes in the DLL, the usage of `dumpbin.exe` to examine the export table. Then you can try to use the DLL in another "C++ DLL", then try to change compiler options and examine the memory management problems together with the names of undecorated exported functions and the problem with different threading models. COM defines rules to clear the questions and more. – Oleg Oct 03 '16 at 16:00
  • You are missing the point of C++/CLI entirely. You **do not** have to expose C++ signatures, at all. You compile your C++ class into the same assembly, that exposes the managed interface, through a `ref class` wrapper. You do not have any of the complications that you are trying to solve with a standardized ABI (COM in this case). The problem you insist on solving does not exist. To see this, you need to understand C++/CLI (you don't, obviously). I strongly suggest that you read up on C++/CLI. – IInspectable Oct 03 '16 at 16:09
  • @IInspectable: Look at the question, which was asked 6 years ago. You will read about **"native C++ DLL"**. Compiling of "C++ class into the same assembly" is the out of scope. .Net assembly is the further development of COM ideas. Moreover I wrote you before, that I have no interest in any discussion about the subject. By the way C++ is out of my interests since many years. It was interesting for my 20 years ago, but not today. – Oleg Oct 03 '16 at 16:25
  • You need to pay attention to detail here. The OP has **source code**, that currently compiles to a native DLL. They would now like to make that functionality available to .NET. The obvious choice is a mixed-mode C++/CLI assembly, where unmanaged C++ code still compiles to native object code, with all C++ signatures **private** to the assembly. Nothing of that ever surfaces. The assembly exposes a managed `ref class` that wraps the native functionality. Whatever, your answer is crap, and your comments have re-instated the fact, that you have not the **slightest** clue on the subject matter. – IInspectable Oct 03 '16 at 16:34
  • *"Compiling of 'C++ class into the same assembly' is the out of scope."* - **That** is precisely, what [mixed-mode assemblies](https://msdn.microsoft.com/en-us/library/x0w2664k.aspx) are for. I'm a bit irritated at the complacency and arrogance you deliver, with nothing to offer on the subject at hand. Let's just hope your customers don't find this answer, or worse, the comments. – IInspectable Oct 03 '16 at 16:40
  • @IInspectable: Leave me alone! I wrote you before that I have no interest about the discussion on the subjects, where I have no interest since many years. If you will continue posting your comments I will ask moderator to stop it. – Oleg Oct 03 '16 at 18:30
  • 1
    What exactly is your issue? You wrote an answer, that's more than a mile off. I voted on it, down, and explained my vote. You first insisted, that you cannot be wrong, next you went personal, and now you lost interest. If that is the case I would strongly advice to delete this answer. It is based on so little knowledge that it's only natural to be wrong. If you don't feel like discussing this, simply don't talk back, or silently delete this answer. – IInspectable Oct 03 '16 at 18:41
0

The C++ project file needs the /clr option. This can be set for the whole project on the general tab, I believe, or set on individual files.

Once the clr option is specified Visual Studio will build that class using C++/CLI.

MrSlippers
  • 459
  • 1
  • 6
  • 14
  • That alone does nothing, to make native (unmanaged) code accessible to .NET. The `/clr` switch merely allows to use the C++/CLI language extensions, that can be used to model CLR-visible interfaces for use by .NET code. It doesn't automagically compile native code into something else (unmanaged code still compiles to native object code, not MSIL). – IInspectable Oct 03 '16 at 15:45