3

I have a public ref class in a C++/CLI assembly (MyAssembly) containing a public static method that accepts native parameters.

#pragma make_public(nativeTypeA)

namespace namespaceA
{ 
    public ref class MyClass : namespaceB::MyClass
    {
    public:
        static managedTypeA ^ MethodA(nativeTypeA param);
        static managedTypeB ^ MethodB(nativeTypeB param);
    }
}

I would like to expose this method to another C++/CLI assembly. The managed assembly compiles fine but the assembly that references it (CallingAssembly) generates the following warning for MethodB:

warning C4679: 'namespaceA::MyClass::MethodB' : could not import member
This diagnostic occurred while importing type 'namespaceA::MyClass ' from assembly 'MyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. 

I cannot use make_public on nativeTypeB because it is a typedef of a templated class, however, I am using make_public for non-templated native types (e.g. nativeTypeA) and it works (i.e. no C4679 when compiling CallingAssembly). Instead of using make_public, I have declared the native class public and used __declspec(dllexport) in the native header via preprocessor directives as suggested in this post. It was also necessary to conditionally exclude the "public" modifier (via CLR_ACCESS_MODIFIER) as the class is also included in other native projects:

#ifdef MANAGED
#define CLR_ACCESS_MODIFIER public 
#ifdef MYASSEMBLY_DEF
    #define MYASSEMBLY_LINKAGE __declspec(dllexport)
#else
    #define MYASSEMBLY_LINKAGE __declspec(dllimport)
#endif
#else
#define MYASSEMBLY_LINKAGE
#define CLR_ACCESS_MODIFIER
#endif

template<>
CLR_ACCESS_MODIFIER class MYASSEMBLY_LINKAGE nativeTypeB<TT> : public nativeTypeB_base<TT> {
...
}

I have also done this for the base class of nativeTypeB (necessary in order to compile), and its typedef:

typedef public nativeTypeB<TT> MYASSEMBLY_LINKAGE nativeTypeB;

I'm not sure whether the line above is necessary, but C4679 still occurs either way.

I've done the usual checks: the MANAGED preprocessor directive is defined both projects; MYASSEMBLY_DEF is defined in MyAssembly; and I have added a reference to MyAssembly in CallingAssembly as well as MyAssembly.lib to its link line. The project build order is correct and there are no missing dependencies but I am still getting C4679.

I could change the interface to accept non-templated types but I don't really want to do this as it will lead to code bloat and is less elegant. This post mentions that the normal use of "public" in my native class should work.

Can anyone help?

Thanks in advance!

Community
  • 1
  • 1
greenback
  • 1,506
  • 2
  • 17
  • 29
  • That just isn't going to work, templates don't have external linkage. Use a plain old #include. – Hans Passant Jun 22 '13 at 17:34
  • Can you elaboarate on how to accomplish this using a #include? If I simply #include MyClass.h in the caller's header, I get exactly the same C4679 warnings plus a slew of other errors, e.g. class type redefinition, due to there being eponymous classes in both assemblies. I tried making MethodB private and invoking it from a public proxy method inside MyAssembly, by this did not remove the warnings, which seems surprising given that the caller shouldn't have visibility of private methods. – greenback Jun 22 '13 at 20:44
  • possible duplicate of [Best workaround for compiler error C2158: make\_public does not support native template types](http://stackoverflow.com/questions/4121249/best-workaround-for-compiler-error-c2158-make-public-does-not-support-native-te) – Ben Voigt Jun 23 '13 at 16:07
  • Agreed. I like solution 2 in the linked post above. – greenback Jun 23 '13 at 17:29
  • I could probably achieve what Hans suggests with some refactoring. The same topic is discussed here: http://stackoverflow.com/questions/12800262/c-cli-make-public-for-template-type?lq=1 – greenback Jun 23 '13 at 17:33

1 Answers1

0

Passing objects of native classes across DLL boundaries has never been a good idea, because it's so very easy to violate the One Definition Rule.

C++/CLI does nothing to help this, instead it provides the ability to generate managed types which are specifically designed for sharing across assemblies. It also prevents you from courting disaster (ODR violations) by sharing native types. You can use the make_public pragma to override this, but with restrictions (such as no templates).

The better way to share native types is via COM-style interfaces.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thanks - it's clear that what I was trying isn't supported. I will revise the interface to accept a non-templated type. – greenback Jun 23 '13 at 17:27