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开发者_C百科 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).
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();
        }
    }
}
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.
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
 
         
                                         
                                         
                                         
                                        ![Interactive visualization of a graph in python [closed]](https://www.devze.com/res/2023/04-10/09/92d32fe8c0d22fb96bd6f6e8b7d1f457.gif) 
                                         
                                         
                                         
                                         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论