C++/CLI in Action

Nishant Sivakumar

Mentioned 7

A guide to programming with C++/CLI covers such topics as delegates and arrays, stack semantics, mixed-mode programming, and interoping Windows Forms with MFC.

More on Amazon.com

Mentioned in questions and answers.

I read that GC (Garbage Collectors) moves data in Heap for performance reasons, which I don't quite understand why since it is random access memory, maybe for better sequential access but I wonder if references in Stack get updated when such a move occurs in Heap. But maybe the offset address remains the same but other parts of data get moved by Garbage Collectors, I am not sure though.

I think this question pertains to implementation detail since not all garbage collectors may perform such optimization or they may do it but not update references (if it is a common practice among garbage collector implementations). But I would like to get some overall answer specific to CLR (Common Language Runtime) garbage collectors though.

And also I was reading Eric Lippert's "References are not addresses" article here, and the following paragraph confused me little bit:

If you think of a reference is actually being an opaque GC handle then it becomes clear that to find the address associated with the handle you have to somehow "fix" the object. You have to tell the GC "until further notice, the object with this handle must not be moved in memory, because someone might have an interior pointer to it". (There are various ways to do that which are beyond the scope of this screed.)

It sounds like for reference types, we don't want data to be moved. Then what else we store in the heap, which we can move around for performance optimization? Maybe type information we store there? By the way, in case you wonder what that article is about, then Eric Lippert is comparing references to pointers little bit and try to explain how it may be wrong to say that references are just addresses even though it is how C# implements it.

And also, if any of my assumptions above is wrong, please correct me.

Looking at C++\CLI In Action, there's a section about interior pointers vs pinning pointers:

C++/CLI provides two kinds of pointers that work around this problem. The first kind is called an interior pointer, which is updated by the runtime to reflect the new location of the object that's pointed to every time the object is relocated. The physical address pointed to by the interior pointer never remains the same, but it always points to the same object. The other kind is called a pinning pointer, which prevents the GC from relocating the object; in other words, it pins the object to a specific physical location in the CLR heap. With some restrictions, conversions are possible between interior, pinning, and native pointers.

From that, you can conclude that reference types do move in the heap and their addresses do change. After the Mark and Sweep phase, the objects get compacted inside the heap, thus actually moving to new addresses. The CLR is responsible to keep track of the actual storage location and update those interior pointers using an internal table, making sure that when accessed, it still points to the valid location of the object.

There's an example taken from here:

ref struct CData
{
    int age;
};

int main()
{
    for(int i=0; i<100000; i++) // ((1))
        gcnew CData();

    CData^ d = gcnew CData();
    d->age = 100;

    interior_ptr<int> pint = &d->age; // ((2))

    printf("%p %d\r\n",pint,*pint);

    for(int i=0; i<100000; i++) // ((3))
        gcnew CData();

    printf("%p %d\r\n",pint,*pint); // ((4))
    return 0;
}

Which is explained:

In the sample code, you create 100,000 orphan CData objects ((1)) so that you can fill up a good portion of the CLR heap. You then create a CData object that's stored in a variable and ((2)) an interior pointer to the int member age of this CData object. You then print out the pointer address as well as the int value that is pointed to. Now, ((3)) you create another 100,000 orphan CData objects; somewhere along the line, a garbage-collection cycle occurs (the orphan objects created earlier ((1)) get collected because they aren't referenced anywhere). Note that you don't use a GC::Collect call because that's not guaranteed to force a garbage-collection cycle. As you've already seen in the discussion of the garbage-collection algorithm in the previous chapter, the GC frees up space by removing the orphan objects so that it can do further allocations. At the end of the code (by which time a garbage collection has occurred), you again ((4)) print out the pointer address and the value of age. This is the output I got on my machine (note that the addresses will vary from machine to machine, so your output values won't be the same):

012CB4C8 100
012A13D0 100

Thus far I've figured out out I needed to recompile the library as a .dll instead of a .lib, enable /clr and /EHa instead of /EHsc. Now I've got a managed dll which I've added as a reference in my C# project.

Now how do I use it?

I'm prepared to write some wrappers, but I don't know where to begin or how to "see" what functions I've gained access to. I've read a little bit about how the class names and functions might be mangled by the compiler... do I need to go back and add __declspec exports everywhere (if so, how?), or is there an option in VS2010 that says "don't mangle it!"?

The C++ library in question is still under active development, so I'm hoping I can modify the C++ library as little as possible and just recompile it periodically with a few switches, and then expose the new functionality as I need it.

If you are going to compile your C++ (if originally was unmanaged C++) you will need to do much more than just add the /clr switch. In order for C# to use the DLL you will need to create managed classes and other types based on CTS which are compatible with C# (.NET).

See and ref classes.

A good book to read about the subject (IMHO) is this one

I've done the other way around (Calling pure C++ code from .Net) with C++/CLI and it worked (for the most part).

How is the native->c++/cli direction done?

I really don't want to use COM interop...

The book C++/CLI in Action has a chapter named Mixing Managed and Native Code and inside the chapter, under Working With Interop Mechanisms heading, it talks about both accessing a managed library from native code and accessing a native library from managed code. It did help me get the concepts when I read it once upon a time.

Is it possible to use a C++ .lib file from within a C# program?

What you need is a managed wrapper (C++/CLI) around the native C/C++ library that you are working with.

If you are looking for any C++/CLI book I'd recommend Nishant Sivakumar's C++/CLI in Action

I've an app written C & C++. Now, I need to provide a GUI for this app. MFC is the best option for me. But I'm not familiar with MFC.

So can I use .NET to build GUI for this? If so, How? Please be clear.

If I can use .NET I guess I can use WPF too right?

Depends on if you want to learn another language? If you choose the C++/CLI or C# route you will have to get familiar with those languages before you even start with your GUI. Yeah MFC isn't the greatest but at least you can still use C++ with it. And that seems to be what Microsoft wants you to use since most of their video tutorials are MFC based: http://msdn.microsoft.com/en-us/visualc/bb693459.aspx

If you choose the WinForms C++/CLI route Visual Studio actually ships with a template for this. Even 2010 doesn't ship with a WPF project template like C# though so you should get the message that Microsoft wants you to use C# for GUI stuff.

Anyways, if it's a trivial app or program you are porting it's not that hard using WinForms. Actually, it's just a bit harder than using C# since you get to use the same GUI editor in Visual Studio but you have to write a lot more of the code by hand than using C#.

And you have to know Microsoft's C++/CLI since the template will autogenerate code in that and you need to understand what it does so you can ignore most of it.

Ivor Horton's Beginning Visual C++ 2010 and Visual C++ 2008 How to Program (2nd Edition) ~ Paul J. Deitel, Harvey M. Deitel are 2 of the only books I've seen that cover WinForm/C++/CLI programming so you might want to look at that or just go with C# as everyone recommends.

This book also deserves particular mention since it covers advanced topics and using WPF with C++/CLI: C++/CLI in Action (Manning)

OS : xp
IDE : VS 2008
In the project that i'm doing in visual C++ i have declared a std::vector inside managed class as so

std::vector<pts> dataPoints;//this gives error c4368 : mixed type not allowed 

but this works

std::vector<pts> * dataPoints;//a pointer to the vector  

i then have created this vector on the free store as so in the constructor of the managed class

dataPoints = new std::vector<pts>(noOfElements,pts());//which is not so attractive.

the reason i need vector is because there is file that i'm reading through the ifstream and storing those values in the vector.
Q1) why is that i'm able to declare a pointer to object of native type(i guess)but not an object? furthermore, prior to trying vector i tried the managed array as so

cli::array<Point> dataPoints //and i defined it later.

but when i do this

ifile >> dataPoints[i].X;   

it gives an error c2678 : operator= is not overloaded for int!!.
Q2) why is it that i cant use a managed code here. At first i thought it might be a wrapper class Int but then autounboxing(conversion operators) should take care of it?or is it that Point::X is qualified with property and thus is not recognized as normal int? what am i missing?. this is the reason i went for vector and pts solution.
pts is as follows

 struct pts
{
  int X, int Y;
  pts() : X(0),Y(0){}
  pts(int x,int y) : X(x),Y(y){}
};//this i created to store the data from the file.

You can't directly contain a native type within a managed type: this is just a restriction on C++/CLI. I'm thinking this might be to do with the possibilities of pointers within the native type. If the native type is directly within the managed type, then when managed objects get shuffled around during garbage collection, then these pointers would point to the original, now incorrect, memory.

Therefore the native object needs to be on the heap, so that its internals don't get changed by garbage collection. So you need to hold the vector as a pointer, and delete it appropriately. Note that the latter isn't entirely trivial, and you need to have some knowledge of C++/CLI (which differs subtly from C#). See http://msdn.microsoft.com/en-us/library/ms177197(v=vs.100).aspx.

Looking at the last time I did this, in my file I had

public:
    !NetClass();
    ~NetClass() { this->!NetClass(); } // avoid arning C4461
private:
    class NativeImpl* const m_pImpl; // can't contain NativeImpldirectly

And in the cpp file I had

NetClass::!NetClass()
{
    // implement finalizer in ref class
    delete m_pImpl;
}

You might just want to use the pimpl idiom here if you have more than one native class to contain. See Why should the "PIMPL" idiom be used?.

Finally, I last did this quite a while ago, and I'm just saying what worked for me at the time. If you're doing this, you really need to know what you're doing. I used a book called C++/CLI in Action, which I'd recommend.

Edit

This article on STL/CLR looks interesting: http://blogs.msdn.com/b/nikolad/archive/2006/06/16/stlclr-intro.aspx. To quote

STL/CLR, originally called STL.NET, is an implementation of Standard Template Library (STL) that can operate with objects of managed types. VC++ already has implementation of STL, however it is currently working only with native types.

(I can't really help on your Q2)

I have a renderer written in C++ and directX. I now want to write a (level / scene / UI) editor and if possible / realistic I would prefer to write the interface to my editor in C#/.net

Is this at all feasible, without going down a route of managed c++? Can I expose the necessary interface from my renderer to a C# app, without managed c++?

Writing a wrapper in C++/CLI would be easier to accomplish (IMO) than using Managed C++. I've found it quite easy to understand and started with only a cursory understanding of good ol' C++.

Also, the C++/CLI syntax is nicer than the Managed C++ syntax.

I would recommend this book if you go down that road.