MSDN > 論壇首頁 > Visual C++ Language > C++/CLI /CLR Managed Support in Native Library
發問發問
 

已答覆C++/CLI /CLR Managed Support in Native Library

  • Friday, 28 July, 2006 8:19YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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

解答

  • Friday, 28 July, 2006 8:39nobugzMVP, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆
    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...
  • Friday, 28 July, 2006 22:53einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    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.

所有回覆

  • Friday, 28 July, 2006 8:39nobugzMVP, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆
    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...
  • Friday, 28 July, 2006 16:10Jonathan Caves - MSFT版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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.

  • Friday, 28 July, 2006 16:13nobugzMVP, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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?




  • Friday, 28 July, 2006 16:29nobugzMVP, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Make sure you use the Object Browser in C#, not in C++
  • Friday, 28 July, 2006 17:06YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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!
  • Friday, 28 July, 2006 17:11Jonathan Caves - MSFT版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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 {
             // ...
          };
    }

     

  • Friday, 28 July, 2006 17:24Ayman Shoukry - MSFT版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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
  • Friday, 28 July, 2006 17:57YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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



  • Friday, 28 July, 2006 18:33nobugzMVP, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Try using LibTorrent.myFooSpace;
  • Friday, 28 July, 2006 18:50Jonathan Caves - MSFT版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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.

  • Friday, 28 July, 2006 20:19YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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
  • Friday, 28 July, 2006 20:51einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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.

  • Friday, 28 July, 2006 21:11einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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).

  • Friday, 28 July, 2006 21:35YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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.


  • Friday, 28 July, 2006 21:48Jonathan Caves - MSFT版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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.

  • Friday, 28 July, 2006 21:52einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    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.

  • Friday, 28 July, 2006 22:08YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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
     

  • Friday, 28 July, 2006 22:16YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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.
  • Friday, 28 July, 2006 22:36einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Neither reflector nor the object browser finds the myFooSpace.Foo class in that .dll. Did you include the right one?
  • Friday, 28 July, 2006 22:50YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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.
  • Friday, 28 July, 2006 22:53einaros版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    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.

  • Friday, 28 July, 2006 23:11YourMom 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    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