Microsoft Developer Network > Domovská stránka fór > Visual C++ Language > C++/CLI /CLR Managed Support in Native Library
Odeslat dotazOdeslat dotaz
 

OdpovědětC++/CLI /CLR Managed Support in Native Library

  • 28. července 2006 8:19YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Hi,

    I have a C++ project, a .dll project in Visual Studio 2005, which uses all native C++.  I was able to compile the project with the /clr option  (just /clr for common language runtime support).  I am able to add the a reference to the dll with another C++ project, which is also compiled with the /clr option, and the entire application runs fine.

    The problem comes when I try adding the .dll project reference to a test C# project and add a "using MyCPPNamespace" to my C# class.  I don't see the new C++ project namespace anywhere within my intellisense in the C Sharp project and I can't just add it as a using.

    I thought compiling my native C++ project with the /clr option allowed us to add references to these projects in other managed language projects.  Am I missing something here?  Please help me, this is a very urgent matter.

    Thanks in advance!

    Kind Regards,
    Thomas Goddard
    www.thomasgoddard.com

Odpovědi

  • 28. července 2006 8:39nobugzMVP, ModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět
    There's nothing special about an assembly created by the C++ compiler and linker vs one made by the C# compiler.  Try using View + Object Browser to verify that you can see the namespace and the classes in the assembly.  Don't rely too much in IntelliSense, its got problems.  Just try to create a class from the assembly in your code...
  • 28. července 2006 22:53einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět

    In any case, with the amount of noise in your build log (__fastcall being incompatible with /clr and so forth), I suggest you make a simple clr proxy dll instead. Keep libtorrent as a pure native dll and export the proper c++ classes. Add a second dll with a managed interface to these classes.

    This could help remove the issues at hand, as well as any unwanted effects of compiling a ton of libraries (like Boost) with /clr.

    Keep in mind though, all third party libraries should remain hidden for the managed proxy code using the native interface -- or else you'd have to include boost and other headers again, and you'd be back in the tar pit.

Všechny reakce

  • 28. července 2006 8:39nobugzMVP, ModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět
    There's nothing special about an assembly created by the C++ compiler and linker vs one made by the C# compiler.  Try using View + Object Browser to verify that you can see the namespace and the classes in the assembly.  Don't rely too much in IntelliSense, its got problems.  Just try to create a class from the assembly in your code...
  • 28. července 2006 16:10Jonathan Caves - MSFTModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    Just compiling your code with /clr does not make your classes accessible from C# - they are still native C++ classes which is something that C# knows nothing about. All that compiling with /clr has done is enable your code to run on the CLR it does not make it interoperable with other .NET languages. In order to be able to interoperate you need to create some classes that are accessible from other .NET languages. To do this you need to use C++/CLI - something like:

       public ref class MyClass {
          // ...
       };

    Here is  good initial introduction to the syntax of C++/CLI.

  • 28. července 2006 16:13nobugzMVP, ModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    My apologies for my poor response; my post was marked as the answer by the MSFT C++ program manager. Please don't hesitate to unmark it.

    Without having any code to look at, we need to guess what might be the problem. Things to check:
    - Did you add a reference to the DLL?
    - Did you use "ref class" to declare the C++ classes?
    - When you say "shows my dll's structure", do you see the classes?
    - When you say "native code classes", do you mean C++/CLI classes or C++ classes?




  • 28. července 2006 16:29nobugzMVP, ModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Make sure you use the Object Browser in C#, not in C++
  • 28. července 2006 17:06YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Hi Jonathan,
    Thank you for the detailed response and your quick response at that. You're saying that I can make some new C++/CLI files, alongside my native C++ files which essentially just makes calls to my native C++?

    I tried the above solution by adding the following code.
    #pragma once
    #include "includes/mynativeclass.hpp"

    using namespace someNativeSpace;

    namespace myFooSpace
    {
    ref class Foo
    {
    public:

    Foo(void)
    {
    nativeclass^ test = new nativeclass();
    test.whatever();
    }
    };
    }

    Then I compiled and added the project reference to my C# project. After adding the reference I tried this:

    using System;
    using myFooSpace;

    namespace Test
    {
    class Class1
    {
    Foo foo = new Foo();
    }
    }

    Of course there was still no intellisense and I simply typed out the namespace and the class intantiation.

    When I tried compiling the C# project I received an error that the namespace myFooNamespace did not exist. The C++ project still compiled fine.

    nobugz:
    These are native C++ classes (not C++/CLI), no ref was added at all. I see the classes in the object browser and there is a reference to the assembly.

    What else should I try? I can send you guys the solution with some instructions on getting it setup in your dev environment (if you need it to compile) but the setup process requires an open source library called boost. Let me know if you want the source to the solution so you can test it out on your own.

    If you have any other suggestions, I am happy to try them.

    Thank you!
  • 28. července 2006 17:11Jonathan Caves - MSFTModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    There are a couple of problems with this. The first I suspect must be a typo otherwise the code wouldn't compile - it should be:

       nativeClass* test = new nativeClass();

    The second issue is probably the cause of your problem. The definition of the class needs to be visible to the C# code. So you need to define it as:

       namespace myFooNamespace {
          public ref class Foo {
             // ...
          };
    }

     

  • 28. července 2006 17:24Ayman Shoukry - MSFTModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    My appology, I marked nobugz's post as an answer by mistake.

    Thomas, have you tried the last post by Jonathan! I tried it on my machine using a simple example and it worked.

    Thanks,
    Ayman Shoukry
    VC++ Team
  • 28. července 2006 17:57YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Ok here is a screenshot with the project properties of the C++ project as well as the C# project and source.

    I am still receiving the same errors:

    Error 1 The type or namespace name 'myFooSpace' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Program.cs 2 7 Test
    Error 2 The type or namespace name 'myFooSpace' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Class1.cs 2 7 Test
    Error 3 The type or namespace name 'Foo' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Class1.cs 8 9 Test

    Here is a view of the Object Browser as well

    Thanks,
    Tommy



  • 28. července 2006 18:33nobugzMVP, ModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Try using LibTorrent.myFooSpace;
  • 28. července 2006 18:50Jonathan Caves - MSFTModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    I still see his code:

    torrent^ test = new torrent();

    This should not compile and it may explain why the C# project can't see the C++ assembly - I would check to ensure that your C++ assembly as actually built successfully.

  • 28. července 2006 20:19YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Either way it's the same problem * or ^.

    Error 1 The type or namespace name 'myFooSpace' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Program.cs 2 7 Test
    Error 2 The type or namespace name 'myFooSpace' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Class1.cs 2 7 Test
    Error 3 The type or namespace name 'Foo' could not be found (are you missing a using directive or an assembly reference?) C:\Documents and Settings\Thomas Goddard\Desktop\libtorrent\test\Test\Class1.cs 8 9 Test

    I tried LibTorrent.myFooSpace as well. What's missing?

    I am using the following preprocessor directives:
    WIN32
    WIN32_LEAN_AND_MEAN
    _WIN32_WINNT=0x0500
    UNICODE
    You can see these in the build log below.  I get lots of warnings but 0 errors, LibTorrent.vcproj compiles and links fine.

    build log
  • 28. července 2006 20:51einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    In your C# code, try loading the native/cli dll through reflection, e.g.

    Assembly asm = Assembly.LoadFile("path to dll");
    Type sometype = asm.GetType("'myFooSpace.Foo");

    This may, if nothing else, help debugging the issue.

    Make sure that you point to the right dll and try building both with release configuration.

  • 28. července 2006 21:11einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    Also, a side note. Wouldn't /clr make all the code compile as managed by default? I thought that was why the managed/unmanaged pragmas were provided.

    If this was previously a non-clr dll project, you should at least make sure that your DllMain is unmanaged, to avoid further issues (like loader locks).

  • 28. července 2006 21:35YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    einaros,
    Thank you for taking the time to reply to my issue.  I went ahead and loaded the assembly using reflection and here is the result.

    You'll notice that entry point is null and sometype is null as well.


  • 28. července 2006 21:48Jonathan Caves - MSFTModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    I'm sorry to keep harping on about this but the '^'/'*' issue is important. If you use '^' the code should not compile and the assembly will not be created - but it looks like C# compiler can find the assembly but it can't find any types in the assembly. This tells me that the C# compiler might be loading a stale version of the assembly so that no matter what changes you make to the C++ assembly (even introducing errors that stop it from building) the C# project is still building against the older version. Even if fix the C++ assembly so that it should work the C# compiler is still using the older version.

    I would check where the final output of C++ build process is being created and/or checked the timestamp on the version of the assembly that the C# compiler is referenceing.

  • 28. července 2006 21:52einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     

    Entry point being null is normal. Sometype, however ..

    You should point the Assembly.LoadFile to the output directory of the dll project (release/debug), and not the file put in your C#-project output folder (which vs copies there, as you've added a reference to it). With reflection, the reference isn't needed.

  • 28. července 2006 22:08YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Jonathan and einaros,
    Thanks for sticking with me on this...
    Still no luck!
    Here is the latest screen shot

    If you guys can figure this out, I'll get you both one of these
     

  • 28. července 2006 22:16YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Here is the Test Project with the library and test client

    You can run reflector on it and see that the Foo class is NOT in the libtorrent library.
  • 28. července 2006 22:36einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Neither reflector nor the object browser finds the myFooSpace.Foo class in that .dll. Did you include the right one?
  • 28. července 2006 22:50YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    Yes that's the latest one.  I take back my last post about the class showing up in reflector.  That's the most recent DLL with a date and time of the last build.  If I change a character in the source on the vcproj, the build fails.  With the code exactly like the screenshots, I tried a build clean which whiped the directory, and built again, the build completed fine and the dll is back.
  • 28. července 2006 22:53einarosModerátorUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     Odpovědět

    In any case, with the amount of noise in your build log (__fastcall being incompatible with /clr and so forth), I suggest you make a simple clr proxy dll instead. Keep libtorrent as a pure native dll and export the proper c++ classes. Add a second dll with a managed interface to these classes.

    This could help remove the issues at hand, as well as any unwanted effects of compiling a ton of libraries (like Boost) with /clr.

    Keep in mind though, all third party libraries should remain hidden for the managed proxy code using the native interface -- or else you'd have to include boost and other headers again, and you'd be back in the tar pit.

  • 28. července 2006 23:11YourMom Uživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaileUživatelské medaile
     
    I did exactly as you said in your previous post.  I created a new separate project, managed C++/CLI project which contains a reference to the unmanaged(native) C++ .lib file.  I added the required header files to include, in the managed project, and compiled it with a simple call to the native code within the managed dll.

    I then reference the managed C++/CLI project from inside the C# project and the classes and namespaces are visible from the C# class.  Problem solved!

    Thank you to everyone for your strong support on this issue.

    Not sure what the main issue was with the original LibTorrent project but I am totally happy with this separate managed dll.

    Cheers and Beers!
    T