Exporting unmanaged class from managed dll  
Author Message
eldiener





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

I have a managed dll in which I have a class whose functions I want to export.

In VS2003 I was able to do this by creating a macro which generates __declspec(dllexport) when the managed dll is being built and __declspec(dllimport) when the managed dll is being consumed. This works fine, an import library is created, and other managed dlls which want to access the functional of this class link to the import library and use that functionality.

In VS2005 when I attempt to do the same thing, I get a compiler error C3395 telling me that I can not use __declspect(dllexport) on a function with the __clrcall alling convention. Evidently compiling this class, even though it is an unmanaged class, in a managed dll uses this calling convention. This was not a problem with VS2003 but evidebtly now it is.

How do I solve this problem Is there a way to change the calling convention for unmanaged classes Do I have to change the calling convention for all unmanaged classes in an assembly or only for those which are exported in one assembly and imported by another assembly


Visual C++8  
 
 
crescens2k





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

Hmm, this is strange, I didn't encounter this problem myself. Did you actually define the unmanaged class in the same namespace as the managed class.

I have not been able to reproduce this myself even with a simple example, my managed and unmanaged class don't affect each other at all.

// test.h

#pragma once

using namespace System;

namespace test {

public ref class Class1
{
// TODO: Add your methods for this class here.
};
}

class __declspec(dllexport) testu
{
public:
testu();
};

This compiles with no problems at all.

Could you post the code you are using. That way we may be able to work something out.



 
 
eldiener





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

The problem has nothing to do with having a managed and unmanaged class in the same assembly or using the same namespace. I realized, after looking at your code above and my own code, that the problem probably has to do with having a function in my unmanaged class which takes a managed type as a parameter or return type. So, in your example above, please try

#include <string>

class __declspec(dllexport) testu
{
public:
static std::string ToCppString(System::String *)
{
if (str == 0)
{
return(std::string());
}
System::IntPtr ptr(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str));
std::string ret(static_cast<const char *>(static_cast<void *>(ptr)));
System::Runtime::InteropServices::Marshal::FreeCoTaskMem(ptr);
return(ret);}
};

The code within ToCppString should not matter as far as the compiler error goes.

The error I get is:

error C3395: 'namespacename::classname::ToCppString' : __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention.

Other static functions within the same class which do not use System::String * do not generate this error.

Also, since I am just trying initially to move my managed C++ VS2003 projects to VS2005, before I start the process of converting my Managed C++ code to C++/CLI, I am compiling with /clr:oldSyntax, which in the IDE would be Project Defaults | Common Language Runtime Support set to Old Syntax.

 
 
Nishant Sivakumar





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

The class you are trying to export is a mixed-mode class - and while it doesn't have any managed members, one of its methods takes a managed type argument - which automatically gives it the __clrcall calling convention. I seriously doubt if such a class can be exported the C++ way.

The problem has nothing to do with having a managed and unmanaged class in the same assembly or using the same namespace. I realized, after looking at your code above and my own code, that the problem probably has to do with having a function in my unmanaged class which takes a managed type as a parameter or return type. So, in your example above, please try

#include <string>

class __declspec(dllexport) testu
{
public:
static std::string ToCppString(System::String *)
{
if (str == 0)
{
return(std::string());
}
System::IntPtr ptr(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str));
std::string ret(static_cast<const char *>(static_cast<void *>(ptr)));
System::Runtime::InteropServices::Marshal::FreeCoTaskMem(ptr);
return(ret);}
};

The code within ToCppString should not matter as far as the compiler error goes.

The error I get is:

error C3395: 'namespacename::classname::ToCppString' : __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention.

Other static functions within the same class which do not use System::String * do not generate this error.

Also, since I am just trying initially to move my managed C++ VS2003 projects to VS2005, before I start the process of converting my Managed C++ code to C++/CLI, I am compiling with /clr:oldSyntax, which in the IDE would be Project Defaults | Common Language Runtime Support set to Old Syntax.



 
 
eldiener





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

There is no such thing as a mixed-mode class. A class is either managed or unmanaged. I understand why you call it mixed-mode however.

I also surmised that the __clrcall calling convention was being used because the function takes a managed type argument.

However in VC++ 2003, I was able to export such a function, and now I can not, so evidently the ability to create a reusable function in Managed C++, dealing with both managed and unmanaged types, has been taken away from me.

So now I must look for a way to have a function, which takes a managed type and unmanaged type, and reuse that function from in an assembly from other assemblies. It would be really hard for me to believe that this can no longer be done in .NET programming.

Any suggestions

 
 
crescens2k





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

There are several suggestions for this, don't use managed parameters or change it to a managed class.. The problem you are dealing with is because of managed parameters in an unmanaged method. There is nothing stopping you from using unmanaged parameters and doing converstion though since you can have managed local variables in an unmanaged method.

Another suggestion is to not have it as a class but just as a set of functions. This is a problem with classes after all.

The final suggestion is to use this as a static library instead of a dynamic library. That could be easier too.

But since you said you are working with old vc2003 code, have you tried compiling it with the /clr:oldsyntax switch



 
 
eldiener





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

Regarding the several suggestions:

1) "don't use managed parameters":

The whole point of my post is that I have functions in my non-managed class which have to deal with managed parameters. Clearly if I have a function converting a System::String * to a std::string, I must use managed parameters.

2) "change it to a managed class":

I could be wrong, and I will try it out, but I am almost sure that when using Managed C++ a managed class can not refer to a C++ template type in any way. Perhaps under VC++ 2005 when using C++/CLI a managed class can refer to a C++ template type but I am working in Managed C++ at least initially to port my code from VC++ 2003 to VC++ 2005..

3) "There is nothing stopping you from using unmanaged parameters and doing converstion though since you can have managed local variables in an unmanaged method":

Since a function is converting from a managed variable ( System::String * ) to an unmanaged return value ( std::string ) there is no way to not pass a managed pointer.

4) "
Another suggestion is to not have it as a class but just as a set of functions.":

This may work since I am really just trying to export functions, which I have put in a class and made static functions of that class. However I would really expect the same problem since if the function uses a managed type, what prevents the compiler from calling that function with the __clrcall calling convention and thus generating the same error

5) "
The final suggestion is to use this as a static library instead of a dynamic library.":

.NET assemblies are never static libraries. If you are telling me to use a plain C++ static library I do not think this can be done when my code refers to .NET types but maybe I am wrong about that.

Finally, regarding your last comment, I am compiling with /clr:oldSyntax, as my previous answer in this thread makes clear. The whole initial point of the thread is that I am moving my code from VC++ 2003 to VC++ 2005 and what worked without error in VC++ 2003 using Managed C++ no longer works in VC++ 2005 using Managed C++.


 
 
eldiener





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

"Another suggestion is to not have it as a class but just as a set of functions. This is a problem with classes after all."

As suspected, this produces the exact same error so the problem is not just with a non-managed class but with a function also which mixes non-managed and managed types.

 
 
Frank Racis





PostPosted: Visual C++ Language, Exporting unmanaged class from managed dll Top

I've been trying to figure out something similar for a few months now. In simplest terms, how to call a function in a DLL that accepts a managed parameter and a native parameter (for instance, a String^ and a CString).

The two obvious ways don't work. As you found out, dllexport won't have anything to do with a managed parameter. I tried the other way around, writing a ref class taking a native parameter. This compiles fine, but won't link, because the type definition isn't shared between the caller and the callee.

Wrapping the managed parameters with gcroot worked, but with a performance penalty.

This shouldn't be that hard - the basic problem is how to get the address of a function in a DLL. DllExport won't help, but if there's another way... Then it occurred to me - this is exactly what a vtable does.

The trick is to make your mixed-mode calls virtual but NOT dllexported. The class constructor MUST be dllexported. The vtable will be populated in the DLL, and will have no problem linking against the member functions. When you call it from your EXE, you need to use a pointer to ensure it will use the vtable instead of trying to link directly to the function. So, for instance: your class would look like:

TESTU.HPP:

class testu
{
public:
 __declspec(dllexport) testu();
 virtual std::string ToCppString(System::String ^str);
};

TESTU.CPP:

testu::testu() {}
std::string testu::ToCppString(System::String ^str) 
{ 
 if (str == nullptr)
  {
  return(std::string());
  }
 System::IntPtr ptr (System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str));
 std::string ret(static_cast(static_cast(ptr)));
 System::Runtime::InteropServices::Marshal::FreeCoTaskMem(ptr);
 return(ret);
}

Calling exe

testu tu;
testu* ptu = &tu;
std::string rval = ptu->ToCppString("SomeManagedString");

It might not be the prettiest thing in the world, but it works, and is about 2 orders of magnitude faster than if you had to wrap the parameter in a gcroot.

-Frank