Managed & Unmanaged type problem;
-
I'm living a trouble with managed c++ that below code doesn't work properly so it has generated following error; test.cpp(25) : error C2440: '=' : cannot convert from 'classB __gc *' to 'void *' Cannot convert a managed type to an unmanaged type Code at following;
typedef struct { void* memberA; } classA; typedef struct { int int_memberB; char* cp_memberB; } classB; __gc class ManagedClass { private: classA m_classA; classB m_classB; public: ManagedClass() { m_classA.memberA = &m_classB; } virtual ~ManagedClass() { } };
How can i solve that problem? Some must watch while some must sleep... OGED -
I'm living a trouble with managed c++ that below code doesn't work properly so it has generated following error; test.cpp(25) : error C2440: '=' : cannot convert from 'classB __gc *' to 'void *' Cannot convert a managed type to an unmanaged type Code at following;
typedef struct { void* memberA; } classA; typedef struct { int int_memberB; char* cp_memberB; } classB; __gc class ManagedClass { private: classA m_classA; classB m_classB; public: ManagedClass() { m_classA.memberA = &m_classB; } virtual ~ManagedClass() { } };
How can i solve that problem? Some must watch while some must sleep... OGEDAhmet Orkun GEDiK posted: Cannot convert a managed type to an unmanaged type You are trying to keep a pointer to a managed object, in an unmanaged class. Managed objects live on the GC heap, which is not the same as regular heap memory. Locations/pointers to managed stuff can actually change during an app's lifetime (which would invalidate your pointer), and .Net does not update pointers in unmanaged objects, only in managed ones. Although there are ways to coerce .Net to reveal the numeric address of managed objects, it would require pinning the managed object first, then using it for a very short period of time before unpinning it. If not, the GC is prevented from managing its heap properly. It would be more appropriate to get a pointer to a managed object (such as m_classB here) for use by an unmanaged object, as needed, and for no longer. If you could explain how you need to use a managed pointer in an unmanaged context, perhaps I could provide a solution. Cheers
-
Ahmet Orkun GEDiK posted: Cannot convert a managed type to an unmanaged type You are trying to keep a pointer to a managed object, in an unmanaged class. Managed objects live on the GC heap, which is not the same as regular heap memory. Locations/pointers to managed stuff can actually change during an app's lifetime (which would invalidate your pointer), and .Net does not update pointers in unmanaged objects, only in managed ones. Although there are ways to coerce .Net to reveal the numeric address of managed objects, it would require pinning the managed object first, then using it for a very short period of time before unpinning it. If not, the GC is prevented from managing its heap properly. It would be more appropriate to get a pointer to a managed object (such as m_classB here) for use by an unmanaged object, as needed, and for no longer. If you could explain how you need to use a managed pointer in an unmanaged context, perhaps I could provide a solution. Cheers
-
Ahmet Orkun GEDiK wrote: Is that mean we cannot use old libraries or structures? No, unmanaged structures can be used, and in general C++ library routines can be mixed-in with MC++. The catch is in how managed and unmanaged code is used together. Managed data can usually be "marshaled" over to unmanaged stuff, but the way your first post was written, an unmanaged type tried to hold a pointer to a managed object, and for an unknown amount of time. Data from managed objects can be copied over to unmanaged code, but unmanaged code should not try to keep pointers to managed objects around. Only managed code should keep pointers around to other managed objects. In other words, managed code is fairly happy referencing unmanaged data, but it's not so simple the other way around.
-
Ahmet Orkun GEDiK wrote: Is that mean we cannot use old libraries or structures? No, unmanaged structures can be used, and in general C++ library routines can be mixed-in with MC++. The catch is in how managed and unmanaged code is used together. Managed data can usually be "marshaled" over to unmanaged stuff, but the way your first post was written, an unmanaged type tried to hold a pointer to a managed object, and for an unknown amount of time. Data from managed objects can be copied over to unmanaged code, but unmanaged code should not try to keep pointers to managed objects around. Only managed code should keep pointers around to other managed objects. In other words, managed code is fairly happy referencing unmanaged data, but it's not so simple the other way around.
-
Ok. Sounds great. But how will i solve my problem ? typdefsampleDlg.cpp(26) : error C2440: '=' : cannot convert from 'SAMPLE __gc *__w64 ' to 'void *' Cannot convert a managed type to an unmanaged type Can you give an example to me ? Ahmet Orkun GEDiK
-
You do not store a managed pointer in an unmanaged object. If you could explain why you wanted to store it, and what it was to be used for, perhaps I could explain a workaround, but without that information, I can't provide a suggestion.
Ok. I'm using a library that uses standart C++ routines. One function need to assignment such as following; RFC_OPTIONS rfc_option; RFC_CONNOPT_R3ONLY rfc_connopt; rfc_option.connopt = & rfc_connopt; type definitions at below; typedef struct { rfc_char_t * hostname; int sysnr; rfc_char_t * gateway_host; rfc_char_t * gateway_service; } RFC_CONNOPT_R3ONLY; typedef struct { rfc_char_t * destination; RFC_MODE mode; void * connopt; rfc_char_t * client; rfc_char_t * user; rfc_char_t * password; rfc_char_t * language; int trace; } RFC_OPTIONS; So as i metioned, rfc_option.connopt = & rfc_connopt; has generate error. Ahmet Orkun GEDiK
-
Ok. I'm using a library that uses standart C++ routines. One function need to assignment such as following; RFC_OPTIONS rfc_option; RFC_CONNOPT_R3ONLY rfc_connopt; rfc_option.connopt = & rfc_connopt; type definitions at below; typedef struct { rfc_char_t * hostname; int sysnr; rfc_char_t * gateway_host; rfc_char_t * gateway_service; } RFC_CONNOPT_R3ONLY; typedef struct { rfc_char_t * destination; RFC_MODE mode; void * connopt; rfc_char_t * client; rfc_char_t * user; rfc_char_t * password; rfc_char_t * language; int trace; } RFC_OPTIONS; So as i metioned, rfc_option.connopt = & rfc_connopt; has generate error. Ahmet Orkun GEDiK
One way to do this would be to keep an unmanaged struct around for passing to RfcOpen() calls. I assume you will get your string data as CLR String types, so you might want to keep them around in a .Net/GC struct for convenience, as done here (see m_RfcConnopt). When m_RfcConnopt has been filled, its data can be copied into unmanaged data. In this example the CLR Strings are converted to char strings, and then copied into C++ strings for long-term keeping (optional).
using namespace System::Runtime::InteropServices;
//a GC struct to hold .Net version of the data, just for convenience here
__gc struct RFC_ConOpt
{
String* sHostName;
Int32 sysnr;
String* sGatewayHost;
String* sGatewayService;
};RFC_ConOpt *m_RfcConnopt; //the managed class that holds the connopt stuff
std::string sHostName, sGatewayHost, sGatewaySvc; //can be kept in class for storage//Before you call RfcOpen()...
IntPtr ptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sHostName);
sHostName = (char*)ptr.ToPointer(); //store in C++ string (optional)
Marshal::FreeHGlobal(ptr); //free temp char stringptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sGatewayHost);
sGatewayHost = (char*)ptr.ToPointer();
Marshal::FreeHGlobal(ptr);ptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sGatewayService);
sGatewaySvc = (char*)ptr.ToPointer();
Marshal::FreeHGlobal(ptr);//get pointers to internal char arrays...
rfc_connopt.hostname = &(*sHostName.begin());
rfc_connopt.gateway_host = &(*sGatewayHost.begin());
rfc_connopt.gateway_service = &(*sGatewaySvc.begin());
rfc_connopt.sysnr = m_RfcConnopt->sysnr;rfc_option.connopt = &rfc_connopt; //<--------
You could skip copying the char strings into the C++ strings here. I just did that to avoid having to remember to call Marshal::FreeHGlobal() later on. The important thing is that .Net's wchar_t strings need to be converted to unmanaged char strings, and that rfc_option.connopt needs to point to an unmanaged array.
-
One way to do this would be to keep an unmanaged struct around for passing to RfcOpen() calls. I assume you will get your string data as CLR String types, so you might want to keep them around in a .Net/GC struct for convenience, as done here (see m_RfcConnopt). When m_RfcConnopt has been filled, its data can be copied into unmanaged data. In this example the CLR Strings are converted to char strings, and then copied into C++ strings for long-term keeping (optional).
using namespace System::Runtime::InteropServices;
//a GC struct to hold .Net version of the data, just for convenience here
__gc struct RFC_ConOpt
{
String* sHostName;
Int32 sysnr;
String* sGatewayHost;
String* sGatewayService;
};RFC_ConOpt *m_RfcConnopt; //the managed class that holds the connopt stuff
std::string sHostName, sGatewayHost, sGatewaySvc; //can be kept in class for storage//Before you call RfcOpen()...
IntPtr ptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sHostName);
sHostName = (char*)ptr.ToPointer(); //store in C++ string (optional)
Marshal::FreeHGlobal(ptr); //free temp char stringptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sGatewayHost);
sGatewayHost = (char*)ptr.ToPointer();
Marshal::FreeHGlobal(ptr);ptr = Marshal::StringToHGlobalAnsi(m_RfcConnopt->sGatewayService);
sGatewaySvc = (char*)ptr.ToPointer();
Marshal::FreeHGlobal(ptr);//get pointers to internal char arrays...
rfc_connopt.hostname = &(*sHostName.begin());
rfc_connopt.gateway_host = &(*sGatewayHost.begin());
rfc_connopt.gateway_service = &(*sGatewaySvc.begin());
rfc_connopt.sysnr = m_RfcConnopt->sysnr;rfc_option.connopt = &rfc_connopt; //<--------
You could skip copying the char strings into the C++ strings here. I just did that to avoid having to remember to call Marshal::FreeHGlobal() later on. The important thing is that .Net's wchar_t strings need to be converted to unmanaged char strings, and that rfc_option.connopt needs to point to an unmanaged array.