Handling an Unmanaged String in a C++/CLI Wrapper - BLOCK_TYPE_IS_VALID, _CrtIsValidHeapPointer - c++-cli

I'm new to C++/CLI but have been coding managed code for many years... apparently too many years. :)
Attempting to write a wrapper for an unmanaged class provided by a 3rd party, and I'm seeing some strange stuff. I'm hoping you all can help me out weed what what is my noobishness and what is actually strange.
CLI Wrapper:
public ref class Wrapper
{
public:
Wrapper(const float* flts, unsigned int fltlen, int offset)
{
_unmanagedClass = new UnmanagedClass(flts, fltlen, offset);
}
~Wrapper()
{
delete _unmanagedClass;
}
String^ getSomeString()
{
string x = _unmanagedClass->getSomeString(); //1
String^ ret = gcnew String(x.c_str()); //2
return ret; //3
}
private:
UnmanagedClass* _unmanagedClass;
};
I should also note that I have these directives in the header;
#pragma managed(push, off)
#include "Unmanaged.h"
#pragma comment(lib, "lib\\Unmanaged_dll.lib")
#pragma managed(pop)
Here's Unmanaged.h;
class UNMANGED_API UnmanagedClass
{
public:
UnmanagedClass(const float* flts, uint fltlen, int offset);
string getSomeString() { return _someString; }
private:
string _someString;
};
This all compiles. Then the strangness/lack of experience kicks in.
When debugging this in DEBUG configuration, UnmanagedClass::getSomeString() appears to be returning a resonable/expected string value. I can see this by setting a breakpoint on //2 and peeking the value of x. If I step to //3, I can see that ret has the value of x. However, if I attempt to step out/over //3, I get a couple of failed assertions (BLOCK_TYPE_IS_VALID and _CrtIsValidHeapPointer) and the debugger stalls, never returning to the managed implementation.
When debugging this in RELEASE configuration, I don't get the failed assertions and I return to my managed implementation, but the string value returned by getSomeString() is garbage where ever I peek it; //2, //3 as well as in the managed implementation.
I've massaged the code in a few different ways to no avail.
I think there is some Mashalling that needs to be done around //2, but I haven't been able to find any thing that really hits home as far as how to marshall that basic_string to a System::String^, or if it's even required. If so, then some help with explicit syntax would be greatly appreciated.
I've also narrowed the call that produces the failed assertions down to //1 by returning return ""; //3. These assertions point to trying to modify/delete memory that dosn't exist on the heap the current runtime has access to. Does that have to do with needing to marshall the return value of UnmangedClass::getSomeString()?
Hoping I'm just missing some simple concept here and there isn't a problem with the 3rd party code. Please let me know if I can provide any more detail, and apologies for my almost complete ignorance of the grand-daddy of all languages.
Thanks in advance for any information or "pointers";
EDIT: Adding C# Managed client implementation;
public unsafe string GetString(List<float> flts )
{
float[] fltArr = flts.ToArray();
Wrapper wrap;
fixed (float* ptrFlts = fltArr)
{
wrap = new Wrapper(ptrFlts , fltArr.Length, 0);
}
var x = wrap.getSomeString();
return x.ToString();
}
EDIT: Adding Dumpbin.exe signature of Unmanged.dll!UnmangedClass::getSomeString()
(public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Codegen::getSomeString(void))

This problem has nothing to do with .NET or C++/CLI, the problem is purely in the native code.
You've violated the One Definition Rule for std::string, if your definition doesn't exactly match what Unmanaged_dll.dll uses, all hell breaks loose. And it sounds as if that DLL is used the debug definition/class layout.

You converted your native string to a Managed string just fine. This article on MSDN, has samples on how to convert between all the different string types that ships on Microsoft platforms:
Having said that, I took your code, and compiled it, and I couldn't get anything to fail. Of course I had to come up with my own way of initializing UnmanagedClass::_someString, which I did by just doing this:
UnmanagedClass::UnmanagedClass(const float* /*flts*/, unsigned int /*fltlen*/, int /*offset*/)
{
_someString = "A few of my favorite things";
}
When I did that, and stepped through this code:
#include "stdafx.h"
#include "Wrapper.h"
int _tmain(int argc, _TCHAR* argv[])
{
Wrapper^ w = gcnew Wrapper(NULL, 0, 0);
System::String^ s = w->getSomeString();
return 0;
}
It worked just fine.
Here is the rest of what I did:
// UnmanagedClass.h
#pragma once
#pragma unmanaged
#include <vector>
class UnmanagedClass
{
public:
UnmanagedClass(const float* flts, unsigned int fltlen, int offset);
std::string getSomeString() { return _someString; }
private:
std::string _someString;
};
And it's implementation:
// UnmanagedClass.cpp
#include "UnmanagedClass.h"
#include <tchar.h>
UnmanagedClass::UnmanagedClass(const float* /*flts*/, unsigned int /*fltlen*/, int /*offset*/)
{
_someString = "A few of my favorite things";
}
And the managed class
// wrapper.h
#pragma once
#pragma unmanaged
#include "UnmanagedClass.h"
#pragma managed
public ref class Wrapper
{
public:
Wrapper(const float* flts, unsigned int fltlen, int offset)
{
_unmanagedClass = new UnmanagedClass(flts, fltlen, offset);
}
~Wrapper()
{
delete _unmanagedClass;
}
System::String^ getSomeString()
{
std::string x = _unmanagedClass->getSomeString(); //1
System::String^ ret = gcnew System::String(x.c_str()); //2
return ret; //3
}
private:
UnmanagedClass* _unmanagedClass;
};
I hope that helps a little.

Related

RunmtimeTypeHandle to type

Here is a sample program that wraps up a managed enum for unmanaged use. I want to be able to get wrapped enums back from unmanaged code and convert them back to managed enums with as little overhead as possible. My current scheme requires creating a GCHandle to the Type object. I was thinking maybe there is a way to use the RuntimeTypeHandle value instead to remove this overhead. Is that possible? Or any other efficiency suggestions anyone has.
public value class Stuff {
public:
enum class Modes { A, B };
};
struct enum_wrap {
intptr_t type;
int value;
};
void g(enum_wrap e);
enum_wrap h();
void f(Stuff::Modes mode)
{
enum_wrap wrap;
wrap.value = (int)mode;
wrap.type = static_cast<intptr_t>(GCHandle::ToIntPtr(GCHandle::Alloc(Stuff::Modes::typeid)));
g(wrap);
// ...
enum_wrap ret = h();
Type^ ret_type = safe_cast<Type^>(GCHandle::FromIntPtr(static_cast<IntPtr>(ret.type)).Target);
Enum^ e_obj = (Enum^)Enum::ToObject(ret_type, ret.value);
Console::Write(e_obj->GetType());
Console::Write(": ");
Console::WriteLine(e_obj);
}
#pragma unmanaged
enum_wrap g_enum;
void g(enum_wrap e) {
g_enum = e;
}
enum_wrap h() {
return g_enum;
}
I know this leaks because of never freeing GCHandles. I already have code that can deal with that if this is the best approach I can find. But I'm hoping to not need the Type objects at all.
Edit 1: Put Modes enum in a class so it works right.

Implicit user-defined cast operator (sometimes) does not work for the const type

I'm attempting to make some of our IJW wrappers between our C++ and our .NET code easier to use.
The following is a test situation with our wrapper platform:
// NativeWrapper.h
#pragma once
template <class T>
public ref class NativeWrapper
{
public:
// ...
operator T* ();
operator T& ();
// ...
};
// Test.h
#pragma once
class Test { /* ... */ };
#pragma make_public( Test )
// TestN.h
#pragma once
#include "NativeWrapper.h"
#include "Test.h"
public ref class TestN : public NativeWrapper<Test>
{ /* ... */ };
// main.cpp
#include "TestN.h"
void f(const Test&) { /* ... */ }
int main()
{
TestN^ t = gcnew TestN();
f(t);
return 0;
}
The implicit cast from TestN^ to const Test& via the user-defined operator Test&() works just fine, as I had expected.
However, when I try this in my production code, something is different. It cannot find the proper conversion. I must do the following:
f((Test&)t);
I haven't been able to identify any fundamental differences between what I'm doing in my test and what I'm doing in the main codebase. The NativeWrapper template is identical.
What types of situations might cause the compiler to fail to use a non-const conversion operator when the only acceptable type is the const reference type?
Thanks.

Type casting in C++\CLI project

I have project which I am compiling with /clr. I have a class like below..
ref class A
{
public:
void CheckValue(void * test);
typedef ref struct val
{
std::string *x;
}val_t;
};
in my implementation I ahve to use something like below..
void A::CheckValue(void *test)
{
a::val_t^ allVal = (a::val_t^)test;
}
in my main I have used like..
int main()
{
A^ obj = gcnew A();
a::val_t valObj = new std::string("Test");
obj->CheckValue((void*)valObj);
}
I am getting type cast error and two places -
obj->CheckValue((void*)valObj);
and at
obj->CheckValue((void*)valObj);
error C2440: 'type cast' : cannot convert from 'void*' to 'A::val_t ^'
This snippet is just to show behavior at my end and I ahve to use it this way only. Earlier I was running it using non /clr so it compiled fine.
Now question I have how can I make this type casting work in C++/CLI type project?
Replace void * with Object^. You can also write a generic version of CheckValue but then there is not much point of having a weak-typed parameter when you have the type in the generic parameter.
A reference handle represents an object on the managed heap. Unlike a native pointer, CLR could move the object around during a function call, so the behavior of a pointer and a reference handle is different, and a type cast would fail. You can also pin the object being referenced using pin_ptr if you really need a void* so CLR would not be moving the object during the function call.
Here is how I would get around the limitation you are seeing, just remove the struct from the managed object, since it contains native pointer types.
struct val_t
{
char* x;
};
ref class A
{
public:
void CheckValue(void* test);
};
void A::CheckValue(void* test)
{
val_t* allVal = (val_t*)test;
}
int main()
{
A^ obj = gcnew A();
val_t valObj;
valObj.x = "Test";
obj->CheckValue((void*)&valObj);
}
Now, if you absolutely need the struct to be managed, here is how to do it:
ref class A
{
public:
void CheckValue(void * test);
value struct val_t
{
char* x;
};
};
void A::CheckValue(void *test)
{
a::val_t* allVal = (a::val_t*)test;
}
int main()
{
A^ obj = gcnew A();
a::val_t valObj;
valObj.x = "Test";
pin_ptr<a::val_t> valPin = &valObj;
obj->CheckValue((void*)valPin);
}

C++/CLI: Passing C++ class ptr to unmanaged method

I've been given a third party C/C++ library (.dll, .lib, .exp and .h) that I need to use in our C# app.
ThirdPartyLibrary.h contains...
class AClass {
public:
typedef enum {
green = 7,
blue = 16
} Color;
virtual int GetData()=0;
virtual int DoWork(Color, char *)=0;
};
void * Func1(int, AClass **aClass);
In my C++/CLI code I have done this...
#include "ThirdPartyLibrary.h"
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Wrapper {
public ref class MyBridgeClass
{
private:
AClass* pAClass;
public:
// C# code will call this method
void AMethod (int x)
{
int y = x+10;
Func1 (y, &(this->pAClass)); // <-- error!
}
}
}
I get a build error that reads...
cannot convert parameter 2 from 'cli::interior_ptr<Type>' to 'AClass **'
with
[
Type=AClass *
]
Cannot convert a managed type to an unmanaged type
Any ideas? Maybe I need #pragma manage/unmanged tags in my C++/CLI?
The reason you're getting that error is because of how managed memory works.
In your managed class, you've got a pointer defined. The address of that pointer is part of the managed object, and can change when the garbage collector runs. That's why you can't just pass &pAClass to the method, the GC can change what that address actually is.
There's a couple things you can do to fix this:
You could create an unmanaged helper class to hold the AClass* member. I'd do this if that pointer needs to stay valid beyond the invocation of this method, or if you have a lot of unmanaged pointers to hold.
struct UnmanagedHolder
{
AClass* pAClass;
};
public ref class MyBridgeClass
{
private:
// must create in constructor, delete in destructor and finalizer.
UnmanagedHolder* unmanaged;
public:
// C# code will call this method
void AMethod (int x)
{
int y = x+10;
Func1 (y, &(this->unmanaged->pAClass));
}
};
If you only need the pointer to be valid within AMethod, and the pointer doesn't need to remain valid after the call to Func1, then you can use a pin_ptr.
void AMethod (int x)
{
int y = x+10;
pin_ptr<AClass*> pin = &(this->pAClass);
Func1 (y, pin);
}

C++/CLI, "constant" reference to a tracking handle

I have spotted something like this in code:
void foo(IList<int>^ const & list ) { ... }
What does this ^ const& mean? I looked in the C++/CLI specification, but found no comments on making constant tracking references, nor the ^& combo.
Is this legal?
This code was probably written by a C++ programmer that used common C++ idiom to write C++/CLI. It is quite wrong, passing a reference to tracking handle is only possible if the handle is stored on the stack. It cannot work if the passed List<> reference is stored in a field of an object on the heap, the garbage collector can move it and make the pointer invalid. The compiler will catch it and generate an error. The ^ is already a reference, no additional reference is needed.
Without the reference, the const keyword doesn't make a lot of sense anymore either. Not that it ever did before, the CLR cannot enforce it. Not that this mattered much here, this code could not be called from any other .NET language. They won't generate a pointer to the tracking handle.
Just fix it, there's little point in keeping bad code like this:
void foo(IList<int>^ list ) { ... }
Example of code that shows that the reference cannot work:
using namespace System;
using namespace System::Collections::Generic;
ref class Test {
public:
IList<int>^ lst;
void foo(IList<int> const &list) {}
void wontcompile() {
foo(lst); // C3699
IList<int>^ okay;
foo(okay);
}
};
It's a reference which is constant to a tracking handle.
It allows you to pass the handle by reference instead of by value. Presumably the author thinks it's more efficient than copying the handle.
If the author meant to make the handle constant he should have used either of
Method(TestClass const ^ const & parameter)
Method(TestClass const^ parameter)
Or alternatively
Method(TestClass const^& parameter) - but the caller must const up the handle first
with
TestClass const^ constHandle = nonConstHandle
An example of each:
// test.cpp : Defines the entry point for the console application.
#include "stdafx.h"
ref class TestClass
{
public:
void setA(int value)
{
a = value;
}
TestClass() :
a(10)
{
}
private:
int a;
};
class TakesHandle
{
public:
void methodX1(TestClass const ^ const & parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
void methodX2(TestClass const^ parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
void methodX3(TestClass const^& parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
TakesHandle takes;
TestClass ^ test1 = gcnew TestClass();
// compiles
takes.methodX1(test1);
// compiles
takes.methodX2(test1);
TestClass const ^ constHandle = test1;
takes.methodX3(constHandle);
return 0;
}