I have two c++/cli dlls (i.e. compiled with /clr) where A.dll references B.dll. In assembly B, I have a method, GetMgdClassB, I'd like to call from assembly A. Here is the code in assembly B (B.cpp):
namespace B
{
public class NativeClassB
{
public:
NativeClassB();
// ...
};
public ref class MgdClassB
{
public:
static MgdClassB ^ GetMgdClassB(const std::vector<NativeClassB *> & vecNativeBs)
{
// ...
vecNativeBs;
return gcnew MgdClassB();
}
};
}
Notice that the method GetMgdClassB takes a std::vector. In assembly A, I attempt to call this method with the following code (A.cpp):
namespace B
{
class NativeClassB;
}
#pragma make_public(std::vector<B::NativeClassB *>)
namespace A
{
void Foo()
{
std::vector<B::NativeClassB *> vecNativeBs;
B::MgdClassB::GetMgdClassB(vecNativeBs);
}
}
When I compile A.cpp, I get the following error:
error C2158: 'std::vector<_Ty>' : #pragma make_public directive is currently supported for native non-template types only
the reason I wanted to add this pragma is because native types are private to the assembly by default. If I remove the pragma I get the following error (as expected):
error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible
since the template instantiation type std::vector<B::NativeClassB *>
is private to the assembly.
Attempted Solutions
1. Use void *, break type safety:
Change the method, GetMgdClassB
to take a void *
and pass the address of the std::vector<NativeClassB *>
to the method. In GetMgdClassB
. I can then static_cast
the passed in void *
to std::vector<NativeClassB *> *
. This, of course, works, but breaks type safety.
2. Create a Managed wrapper for NativeClassB, pass a managed container
Create a managed class, say ref class NativeClassBWrapper
who's sole purpose is to hang on to a reference to the native NativeClassB. Change GetMgdClassB to take a managed container of NativeClassBWrappers (e.g. List<NativeClassBWrapper ^> ^
). This has the downside of having to create and populate a new managed container prior to calling GetMgdClassB, and then within managed class B, I have to repackage it into the the native container std::vector<NativeClassB *>
(since the code in B deals with this type.
Currently, I'm leaning toward going with Solution #1, since (a) it doesn't introduce any performance concerns and (b) I'll only be doing this in a few cases. I don't like losing the type safety, but it seems justifiable given the current deficiency in the compiler's ability to make native template instantiation types visible.
Question:
Are there better work arounds?
Related Question:
C++ CLI error C3767: candidate function(s) not accessible