Getting started with Managed C++
Written by Harry Fairhead   
Tuesday, 17 August 2010
Article Index
Getting started with Managed C++
The Designer

Add a button

With this success behind us let move on and add a button. Each Form object has a Controls collection and you can add control objects to it. For example, as we have already seen there is a Button class, which can be used to instantiate a button object:

Button^ button2=gcnew Button();

 

Once you have the button object you can customise its look using its properties and then you can add it to the Form’s control collection:

dialog1->Controls->Add(button2);

This produces a button without a title in the top lefthand corner of  the dialog box. To position the button we need to use the Point class and the button's Location property.

button2->Location = Point (20, 50);

The only question is why don't we need to allocate Point on the managed heap? The answer is because it's a value type and hence it is perfectly happy being created on the stack. You need to be careful about when something needs to be created on the heap and when on the stack but in the main it isn't too difficult. In particular if you do make a mistake and try say to allocate the Point struct on the heap then you will get an error message when you try to assign the handle to the Location property because its not a handle but a Point.

For a form you are using as a dialog box there is an alternative to overriding the button's event handler. Controls have a DialogResult property, which can be set to a range of constants which product standard dialog box behaviour. For example add the line:

button2->DialogResult= System::Windows::
Forms::DialogResult::OK;

and clicking on the button terminates the dialog box. The Form also has a DialogResult property, which can be tested on exit to see what caused the modal dialog box to terminate.

For example, if we add a textbox we can test the return result and print the contents of the textbox on the console window if the OK button was pressed  by changing the end of the program to read:

 

TextBox^ text1=gcnew TextBox();
text1->Location=Point(10,100);
dialog1->Controls->Add(text1);
dialog1->Controls->Add(button2);
dialog1->ShowDialog();
if(dialog1->DialogResult==System::
Windows::Forms::DialogResult::OK)
{
 Diagnostics::Debug::WriteLine(
text1->Text)
}

 

at the start of the program. Now when the program is run you can enter some text into the textbox, click OK and see it appear in the console window before it vanishes!

If you are familiar with the more direct C/C++ way of creating a dialog box you might be a bit worried that we are accessing properties of the dialog box well after it has been destroyed. Don't worry because what matters is the managed control rather than the underlying "real" windows dialog box. The distinction between the Windows object, i.e. the dialog box, and the framework object, i.e. the Form acting as dialog box, has been blurred. There are properties and methods that you can use in advanced situations to ascertain whether or not the Windows object has been disposed of or not but in the main you can ignore such subtlety.

That is, the dialog box that appears when you show the form can be regarded as just the visual appearance of the Form object – if you don’t understand why I’m making a fuss about framework objects and Windows objects here you probably haven’t tried to use the MFC!

The keyword here is simplicity of use and the framework is wonderfully simple compared with the MFC or the ATL. Of course anything new takes time to learn and I’m sure you could put up a good argument that it was more difficult!

 

Use the Designer

Of course the correct way to create a dialog box is not to create code on the fly in the way that we have been doing but to create a new managed class. This turns out to be even easier. Rather than implementing the class manually we can just use the Designer. Right click on the Header Files in the Solution Explorer and select Add New Item. Select  Windows Form and give it the name Dialog3. Now you have a second form in the project. You can customise this by dragging and dropping a button and a textbox.

To customise the new Form's properties simply right click on the form and select Properties you can set FormBorder to FixedDialog and ControlBox to false to make the form look like a dialog box. Next select button1 and set its DialogResult property to OK. You can also add a Cancel button in the same way. You don't need to write any code to make it work.

To make use of your new dialog class, which has automatically been added to the project you simply need to inlcude it in any code file that needs to make use of it. For example, if you edit the code of the Form1.h code you need to add

#include "Dialog3.h"

The include directive adds the file specified as if the code was in the file you are working on. However this might not be enough to gain access to the classes defined in the file - you have to deal with namespaces. The code generated was in the namespace Forms so we need to add

using namespace Forms; 

in the ,h file. This may not be the best way to organise the namespace and adding a Dialog or Dialog3 namespace seems like a better idea. With these additions you can not add the code to create and use your new dialog box:

Dialog3^ MyDialog=gcnew Dialog3();
MyDialog->ShowDialog();

In nearly all cases it is much easier to use the Designer to create windows and user interfaces in general than to hand code them. Just Include the generated code and make sure you are in the right namespace.

Creating a managed class

 

It is fine to use the Designer for user interface classes but what about creating a general purpose managed class? The big problem with doing this is that while there are lots of examples available most of them use the old __gc syntax which doesn't work under VC++ 2010. All of the __gc (garbage collected) specifiers have been changed:

  • Replace __gc class with ref class.
  • Replace __gc struct with ref struct.
  • Replace __value class with value class.
  • Replace __value struct with value struct.
  • Replace __gc __interface with interface class.

Similarly garbage collected arrays are simply defined as array,

So to create a managed class that adds two numbers together you would use something like:

public ref class VCAdd
{
 public:
 int add(int a,int b)
 {
 return(a+b);
 }
};

And once defined and included in a code file you can use this class just like any other managed class:

VCAdd^ math=gcnew VCAdd();
int result=math->add(1,2);

If you compile the class you can even use the resulting DLL from any other managed language. If you create a new VB application and place a button on a form then to use the new C++ class all you have to do is add:

Imports VCMath

to the start of the program and add a reference to the .DLL in the usual way.

Then in the button’s event handler you can code:

Protected Sub Button1_Click(
  ByVal sender As System.Object,
ByVal e As System.EventArgs)
Dim x As New VCMath.VCadd()
console.writeline(x.add(2,3))
End Sub

Of course the real power of C++, managed or otherwise, is in the access it gives you to low level facilities such as the Windows API and COM. Mixing managed and unmanaged code isn't difficult but best left for another article.


 

If you would like to suggest a topic for our Core C++ section or if you have any comments contact our C/C++ editor Harry Fairhead.

If you would like to be informed about new articles on I Programmer you can either follow us on Twitter, on Facebook or you can subscribe to our weekly newsletter.

 


Further reading

An almost complete check list of changes to upgrade to modern managed C++ can be found at http://msdn.microsoft.com/en-us/library/b23b94s7(VS.80).aspx

 

<ASIN:1590597567>

<ASIN:1430210532>

<ASIN:1430210230>

<ASIN:1590596080>

<ASIN:0735619077>

<ASIN:013045821X>

<ASIN:1932394818>

<ASIN:0201379260>

<ASIN:0201700735>

<ASIN:0735640602>

<ASIN:0672331012>

<ASIN:0470500883>

 



Last Updated ( Saturday, 21 May 2016 )