Mixed management in C++ - c++-cli

I have added a class to my program and tested it. I was really surprised that there was any real errors. Here is the code:
#pragma once
#include "Iingredient.h"
#include <string>
#include <vector>
using namespace std;
ref class Recipe{
private:
string partsName;
vector<Iingredient> ing;
public:
Recipe(){}
};
And here are the errors:
Error 23 error C4368: cannot define 'partsName' as a member of managed
'Recipe': mixed types are not
supported c:\users\user\documents\visual studio
2010\projects\smestras2_l1\Recipe.h 10 1 file2_L1
Error 24 error C4368: cannot define 'ing' as a member of managed
'Recipe': mixed types are not
supported c:\users\user\documents\visual studio
2010\projects\smestras2_l1\Recipe.h 11 1 file2_L1
I googled a bit and found out that its about managed and unmanaged code.
How to fix this? Is it related with manged and unmanaged code or not? if so how?

I agree with others: you shouldn't use C++/CLI in most circumstances, you should use C# (or another "normal" managed language) for that (assuming you want to write a .Net application). C++/CLI is useful mostly in special circumstances, like interoperating between managed and unmanaged code.
If you're sure you want use C++/CLI, you can't put native classes into managed ones. But you can put pointers to native classes there:
ref class Recipe{
private:
string* partsName;
vector<Iingredient>* ing;
};
The code above works. But you have to keep in mind that those are normal native C++ pointers and that means you have to manually delete them. To do that property, you should read about how destructors and finalizers work in C++/CLI.

When defining ref class Recipe, you made it managed. But std::string and std::vector are umanaged types. You are trying to declare native variables in managed class, but it is not allowed.
Seems, you are novice in C++. Just, don't use C++/CLI. Consider C#, if you target .Net or unmanaged C++.

You cannot use unmanaged types in a managed class, ref keyword, because the heap and the managed heap are two different types of memory. To solve this specific problem you can use a managed string type (System::String^). The carrot tells the compiler that the type is a handle to a managed class.
Another way of going about this problem is to use pointers, that way the pointer will be on the managed heap, and the actual memory for that object will be in the standard unmanaged heap, which is where Recipe is located.
To construct your Recipe class you would have to do
Recipe^ recipe = gcnew Recipe();

With no idea of c++-cli, I can try and guess that the problem is that you are defining a reference type and trying to use C++ types inside (a std::string field) rather than whatever the equivalent managed type is (String?).
The reason why this can be problematic is that it mixes resource management approaches. Reference types are intended to be used out of a garbage collector, and unless you implement a destructor or IDisposable will just be ignored once proven that the last reference is lost. On the other hand, to be able to manage the memory in the internal field the std::string destructor must be called.

Related

What's the corresponding C++ native type of C++/CLI System::String^

I need to rewrite a C++/CLI project to native C++ project, by removing or replacing managed codes. I'm not very familiar with C++/CLI,so, what's the corresponding C++ native type of C++/CLI System::String^, is it std::string or std::string*?
For example a C++/CLI function Foo(System::String^ location), rewrite it to Foo(std::string location),is this right?
It's probably std::string though it depends on your ownership intentions. For example, the closest translation of String^ (ignoring the shared memory part for the moment) would be a std::string& which is known as a reference - effectively a pointer except they are never null and cannot be manually de-allocated. A class is more likely to have std::string members (meaning that it owns that data) than std::string& members (meaning it does not own that data)
The other question for function signatures is whether Foo is allowed to mutate the location object. If it isn't, a const std::string& parameter should be used
It's probably not std::string* as 'raw pointers' are quite rare to use in modern C++. You generally create objects on the stack and pass them around using references, allowing RAII to manage the memory - I would definitely read up more on RAII which explains the ownership model and is very important for writing C++

C++/CLI: are local managed variables allowed in unmanaged class methods?

I know gcroot is used for holding a refrence to a managed object in a native class, but what about using managed objects as local variables inside an unmanaged class function ?
The compiler does not seem to generate an error on this, but is it "proper" ? Does it hurt performence?
There is no such thing as a local managed object. All managed objects are stored on the heap, required to let the garbage collector do its job. You could only have a reference as a local variable. A pointer at runtime.
Using an managed object reference in an unmanaged function is possible if you compile that code with /clr or #pragma managed in effect. Such code will be translated to IL and gets just-in-time compiled at runtime, just like normal managed code. It won't otherwise have the characteristics of managed code, there is no verification and you'll suffer all the normal pointer bugs. And yes, it can hurt performance because such code doesn't get the normal optimizer love. The optimizer built in the jitter isn't as effective because it works under time constraints.
Compile native code without the /clr option or use #pragma unmanaged inside your code to switch the compiler on-the-fly.
Managed objects, both values of managed value types (value struct, value class, enum class) and handles to managed reference types (ref struct, ref class) can be used inside code which is compiled to MSIL.
And code that is compiled to MSIL can be part of unmanaged objects (for example, a virtual member function of a standard C++ type can be compiled to MSIL, and the Visual C++ compiler "It Just Works" technology will make sure that the v-table is set up correctly). This is extremely useful when forwarding events and callbacks produced by standard C++ code into the managed GUI world. But it is also applicable if you have an algorithm implemented in managed code (perhaps C#) that you want to call from C++.
As Hans mentions, there are performance implications of switching between MSIL and machine code generation for a particular function. But if you are sitting on a native-managed boundary, then compilation to MSIL and use of the "It Just Works" a/k/a "C++ interop" is by far the highest performance alternative.

How to receive bytes in Managed C++ project from COM plus project

I have a module A in Managed C++, it depends on module B in native C++ which wrapped as COM plus.
In module B, I read bytes from a file. Now I am trying to call the file reading functionality from A. But failed.
Dependency detail: I used tlbimp.exe and generated the interop according to Module B. A referrs to the interop.
I tried to pass an "array^" but only one char was received, which is understandable because marshaling doesn't know the array length and could NOT handle the whole array.
I searched out some recommendation about safe array, but could NOT use it successfully in my projects.
Could somebody help me on this?
Thanks a lot.
If you are going to be talking to your native object via COM, you're going to have to pass the array the COM way.
SAFEARRAY would definitely work, but you don't have to use it. It is a fair amount of work to set up anyway. If neither component is a scripting language or VB6, there is little value to using a SAFEARAY.
COM can marshal the array just fine, you just have to tell it how big it is. The two most common mechanisms in COM to pass (native) arrays are "fixed-sized arrays" and "conformant arrays".
Fixed-size array:
If you know at compile time the size of the array, this is the way to go. Declare your COM method as follows in your IDL:
...
const long ARRAY_SIZE = 1024;
...
HRESULTS MethodAbc(MyClass array[ARRAY_SIZE]);
Marshalling will take care of passing the whole array.
Conformant Arrays:
You declare them as follows in IDL:
HRESULT MethodAbc([size_is(arraySize)] MyClass array[], long arraySize);
This tells COM that the arraySize parameter holds the count of elements.
My experience with CLI is minimal, but I don't think you can just pass a CLI handle. Among other things, I believe you need to pin the pointer so that GC doesn't move the array during the COM call. Others please correct me here if I'm wrong.

c++/cli wrapper question

Is there a recommended way to wrap a native c++ library by c++ cli?
Not sure if one size fits all, but yeah, it is largely a mechanical process. Your ref class wrapper should declare a private member that's a pointer to your native C++ class. Create the instance in the constructor. You'll need a destructor and a finalizer to delete that instance again.
Then for each function in the native C++ class you write a managed version of it. That's almost always a one-to-one call, you simply call the corresponding native method and let C++ Interop convert the arguments. Sometimes you have to write a bit of glue code to convert a managed argument to the native version of it, particularly if your native method uses 8-bit char* or structure arguments.
You'll find that standard pattern in code in my answer here. I also should mention SWIG, a tool that can automate it. Not sure how good it is, never used it myself.

Converting c++ project to clr safe project

I need to work on converting a very huge c++ project to clr safe. The current c++ project has a lot of stuff from c++ like templates, generics, pointers, storage/stream, ole apis, zlib compression apis, inlines etc. Where can I find the datiled document for this type of conversion? Can you suggest some good book to refer to? If anyone of you have done such conversion, can I get some analysis from you?
I'll just cough up the MSDN Library article titled "How to: Migrate to /clr:safe
Visual C++ can generate verifiable components with using /clr:safe, which causes the compiler to generate errors for each non-verifiable code construct.
The following issues generate verifiability errors:
Native types. Even if it isn't used, the declaration of native classes, structures, pointers, or arrays will prevent compilation.
Global variables
Function calls into any unmanaged library, including common language runtime function calls
A verifiable function cannot contain a static_cast Operator for down-casting. The static_cast operator can be used for casting between primitive types, but for down-casting, safe_cast or a C-Style cast (which is implemented as a safe_cast) must be used.
A verifiable function cannot contain a reinterpret_cast operator (or any C-style cast equivalent).
A verifiable function cannot perform arithmetic on an interior_ptr. It may only assign to it and dereference it.
A verifiable function can only throw or catch pointers to reference types, so value types must be boxed before throwing.
A verifiable function can only call verifiable functions (such that calls to the common language runtime are not allowed, include AtEntry/AtExit, and so global constructors are disallowed).
A verifiable class cannot use Explicit.
If building an EXE, a main function cannot declare any parameters, so GetCommandLineArgs must be used to retrieve command-line arguments.
Making a non-virtual call to a virtual function.
Also, the following keywords cannot be used in verifiable code:
unmanaged and pack pragmas
naked and align __declspec modifiers
__asm
__based
__try and __except
I reckon that will keep you busy for a while. There is no magic wand to wave to turn native C++ into verifiable code. Are you sure this is worth the investment?
The vast majority of native C++ is entirely valid C++/CLI, including templates, inlines, etc, except the CLR STL is rather slow compared to the BCL. Also, native C++ doesn't have generics, only templates.
The reality of compiling as C++/CLI is to check the switch and push compile, and wait for it to throw errors.
Rewriting native C++ into safe C++/CLI will result in a code that is syntactically different, but semantically same as C#. If that is the case, why not rewrite directly in C#?
If you want to avoid what is essentially a complete rewrite, consider the following alternatives:
P/Invoke. Unfortunately, I'm unfamiliar whether this would isolate safe from unsafe code. Even if it can perform the isolation, you'll need to wrap your existing C++ code into procedural, C-like API, so it can be consumed by P/Invoke. On a plus side, unless your API is excessively chatty, you get to keep (most of) your native performance.
Wrapping your C++ into out-of-process COM server and using COM Interop to consume it from the manged code. This way, your managed code is completely protected from any corruption that might happen at C++ end and can remain "safe". The downside is a performance hit that you'll get for out-of-process marshaling and the implementation effort you'll need to expend to correctly implement the COM.