16

I am trying to call my C++ library from my C# application (via C++/CLI). I followed the example from this question (for my specific application). The setup of my application is:

  • Project1: C++ Project (I compile this to a DLL)
  • Project2: C++ Project (my CLR wrapper; just the header file per the example above; references Project1)
  • Project3: C# Project (references Project2)

Unfortunately, when I actually go to access the CLR wrapper object in my C# application, I receive the following error:

The type or namespace name 'YourClass' could not be found (are you missing a using directive or an assembly reference?)

Do I have the project setup incorrectly, or is there something else I should be looking into? (Unfortunately, I cannot post the code for proprietary reasons, but it is a very simple bit of code and easily follows the above example.)

Update:

So I did exactly what Chris said to do (see answer below), but I am still receiving a message from my C# application that "The type or namespace name 'MyProgram' could not be found (are you missing a using directive or an assembly reference?). Here is a (mock-up) of my code.

  • Project1 - This is my C++ application. It compiles/works. I have used it elsewhere. (I get a DLL out of this build.)
  • Project2 - Here is my code for my wrapper.

MyWrapper.h

#pragma once

#include "myorigapp.h"

using namespace System;

namespace MyProgram
{
    public ref class MyWrapper
    {
    private:
        myorigapp* NativePtr;

    public:
        MyWrapper() 
        {
            NativePtr = new myorigapp();
        }

        ~MyWrapper() 
        { 
            delete NativePtr;
            NativePtr = NULL;
        }

        void dostuff()
        { 
            NativePtr->dostuff(); 
        }
    }
}
  • Project3 - This is my C# application.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MyProgram;

namespace Testing
{
    class Program
    {
        static void Main(string[] args)
        {
            MyWrapper p = new MyWrapper();
            p.dostuff();
        }
    }
}

Project3 references Project2 which references Project1. Everything builds without errors (except the error I described above in the C# code on the using MyProgram line).

3
  • are you missing a using directive or an assembly reference? Commented Apr 13, 2011 at 23:26
  • you should post some code, if you don't want to post the original thing, perhaps you can extract the relevant parts, simplify and modify some names etc. Commented Apr 14, 2011 at 6:32
  • @Hans @Doc - Updated the question with code and more information. Commented Apr 14, 2011 at 15:47

3 Answers 3

9

Just including the header from a pure C++ application isn't good enough. You need to wrap your unmanaged objects with managed ones in Project2 (i.e. public ref class YourClassDotNet)

#include "YourHeader.h"

namespace MyManagedWrapper
{
    public ref class YourClassDotNet
    {
    private:
        YourClass* ptr;

    public:
        YourClassDotNet()
        {
            ptr = new YourClass();
        }

        ~YourClassDotNet()
        {
            this->!YourClassDotNet();
        }

        !YourClassDotNet()
        {
            delete ptr;
            ptr = NULL;
        }

        void SomeMethod()
        {
            ptr->SomeMethod();
        }
    }
}
Sign up to request clarification or add additional context in comments.

13 Comments

+1. Don't forget to mention that those methods of MyManagedWrapper will typically have to make some type conversion from .NET data types to native C++ data types and vice versa.
@Doc: at your service, I guess?
Manually ensuring the native object is properly freed gets complicated fast. I suggest using a smart pointer instead of duplicating that logic in every wrapper class. Here's one I wrote: scoped_ptr for C++/CLI (ensure managed object properly frees owned native object)
@Doc Brown Yeah it gets pretty gnarly there
@Chris - Thank you for your answer. However, I am already doing this. Project1 and Project2 do build correctly. So, I may be failing to do "using" or an assembly reference correctly. Can you provide insight into this? From what I can tell (in your example) I would have a reference to Project2 from Project3, and I would have "using MyManagedWrapper" at the top of the C# class that wants to use the managed object. Is this correct?
|
4

Okay, well, I now feel dumb.

It turns out that the problem I was having (which I solved a couple weeks ago - just got around to updating this answer) was that I had included the header file (see Chris' answer for that), but I hadn't actually included the CPP file (which is empty other than including the header file).

Once I did this, the DLL compiled correctly and I could call the C++ functions (using C++/CLI) from my C# code.

4 Comments

I tried your example and also generated a dll but I can't use it in the c# program. When I see the dll in the object browser it is empty. I don't think I quite understood your proposed solution.
I'm having the same problem right now, but can't understand your solution. Maybe you can explain it? Thank you
Header file needs to say translator "there's somewhere an implementation of the functionality you use"; and if there's dll from Project1 and header for it - I won't have to care in any CPP (maybe they are not in free access). Do I miss something, or author, or c# + c++ is more complex? Does the next make sense - wrap C++ header with C++/CLI to use in C# & no implementations files of that C++ part, only built library for your architecture? If yes, what CPP you are talking about?
@VladL OP means you need some CPP file in Project2 to make it 'builtable', they had only header file initially. 10 mins after my wonder I got what about answer is. OP doesn't mean CPP from dll. It's a cpp file just to make Proj2 work:)
3

Chris showed you the way to create a managed class that uses unmanaged code inside. There is a lot of that that you can do in C# using unsafe (it's just that hardly anyone does).

However, the reverse is also possible: using .NET types directly from a native type/function.

The thing to watch out for is that any managed pointer has to be marked as such. For this purpose, C++/CLI defines a special type of smartpointer gcroot<T> (mimicking boost::shared_pointer or std::auto_ptr in a way). So to store a managed string inside your C++ class, use the following:

#include <string>
#include <vcclr.h>
using namespace System;

class CppClass {
public:
   gcroot<String^> str;   // can use str as if it were String^
   CppClass(const std::string& text) : str(gcnew String(text.c_str())) {}
};

int main() {
   CppClass c("hello");
   c.str = gcnew String("bye");
   Console::WriteLine( c.str );   // no cast required
}

Note that (if it hasn't been fixed these days) you'll run into a bit of friction with the mismatch between managed null and C/C++ NULL. You can't easily type, as you would expect:

gcroot<Object^> the_thing;
...
if (the_thing != nullptr)
 ...
}

Instead you'd have to use the native style (the smart wrapper gcroot handles this)

gcroot< Object^ > the_thing;
if ( the_thing != NULL ) {} // or equivalently...
if ( the_thing ) {}

// not too sure anymore, but I thought the following is also possible:
if ( the_thing != gcroot<Object>(nullptr) ) {}

Note: I don't have access to a windows machine anywhere near these days, so I've quoted from memory

2 Comments

In order for this to work, you need to turn on CLI for the project (i.e. this doesn't work for a pure C++ app).
Or compile with the /clr flag

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.