April 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Building a .NET Windows Forms App in Visual C++ .NET

  • June 28, 2002
  • By Kate Gregory
  • Send Email »
  • More Articles »

From Kate Gregory's Codeguru column, "Using Visual C++ .NET.

Most people will tell you that you can't build a Windows Forms application in Visual C++ .NET. However, that's not strictly true. What you can't do is use the visual designers to drag, drop, and arrange your buttons, labels, and so on if you're working in Visual C++. Old timers like me remember that the name Visual C++ comes from just that capability. But we also remember that there was always another way to make our user interfaces, creating buttons and labels and the like in code, and setting their size and position with lines of code. All the visual designers do is generate that code for you behind the scenes. And at the moment, they only generate C# or VB.NET code.

In .NET, the code generated by the designers isn't hidden somewhere, or generated only when you build. It's easily accessible within files you probably have open anyway, and that means it's easy to copy. In this column, I'm going to show you how to build your user interface in C#, then do a little editing to turn it into a 100% C++ application. Along the way you'll get some insight into the differences between C# and C++.

It's only fair to mention that MSDN has a sample of a Customization project called the ManagedCWinFormWiz. You copy some folders from the MSDN CD or DVD to specific places on your hard drive, and the next time you choose File, New Project you have an extra choice under C++: Managed C++ Windows Forms Project. Don't get too excited though: there are no steps to this wizard, and it doesn't do very much. It creates a form with a menu and a few controls, so you can see where to hand-add your own code. But you get no help in building your user interface at all. They even forgot to make the simple change that takes away the ugly black command prompt in the background behind your Windows application when it runs. You'll do better with the sample code I provide with this column.

Remember also that the reality of .NET cross-language development means that you could just develop your user interface in C# and work with business objects written in C++. Still, I like to know that I can do it all in one project and all in one language if I choose. I don't like thinking of Visual C++ as limited in any way.

Getting Started

I'm going to start by building a C# application. If you want to follow along, open Visual Studio and choose File, New Project. Select Visual C# Projects on the left and Windows Application on the right. Name the project cs1 to have all your file names and so on match mine. In the forms designer, just quickly drag on a button and a label next to it. (You might have to choose View, Toolbox to have somewhere to drag them from.) The user interface looks like Figure 1.



Figure 1. Click here for larger image

I changed the text (caption) of the button to Greet Me and the label to blank, but left their names as generated. For a real application, you would go to town here creating a complex and beautiful user interface. Next, double-click the button to generate an event handler for it. I just added this line of code:

label1.Text = "Hello!";

If you like, build and run it to assure yourself that it works. Click the button and the label text should change to "Hello!". That's all you need this project for, so exit the app and choose File, Close Solution to close it in Visual Studio.

Creating the C++ application

To create an empty C++ application that will grow to display your Windows Forms application, start by choosing File, New Project. Select Visual C++ projects on the left and Managed C++ Application on the right. Call it cpp1 if you want your file and variables names to match mine. Use notepad to open form1.cs from the C# application, and select and copy all the text, then paste it into cpp1.cpp, right before the _tmain() function.

Differences between C# and C++

Now it's time to set to work changing C# to C++. As you do this, remember the compiler is your friend, and will remind you of any changes you forget to make.The important differences include:

  • C# uses dots to separate namespaces from subnamespaces, namespaces from classes, classes from static member functions, and object references from instance functions. C++ uses the scope resolution operator (::) for the first three, and the member dereference operator (->) for the last.
  • C# returns object references from new; C++ returns pointers. C++ cannot have an instance of a managed object, only a pointer to one, so declarations must be changed from Foo to Foo*.
  • C# allows you to add references to a project with menus; C++ requires a #using statement. (The online help for each class tells you what assembly it is in, such as System.dll, so you can add the appropriate #using statement.)
  • C# repeats the access qualifier (private, public, etc) on each declaration. C++ sets up blocks of members with a given access qualifier.
  • C# allows you to initialize a member variable when you declare it. C++ does not.
  • The C# keyword for a null reference is null; the C++ constant for the null pointer is NULL.
  • In C# when you override a function from the base class, you indicate that you are doing so knowingly with the override keyword: this isn't necessary in C++.
  • Although C# doesn't have a pre-processor, it does have some keywords that start with # that are instructions to the IDE more than to the compiler. These are generally not supported in C++ and must be removed. Two very common examples are #region and #endregion, used in outlining view.
  • C# makes it easy to declare arrays on the fly with brace brackets; C++ does not allow this as an argument to a function. Either create a temporary array to pass or look for another function that doesn't need an array passed to it, and call it multiple times.
  • C# talks to the base class as base. while C++ uses the actual name of the base class and ::.
  • Some classes in the Base Class Library are actually value types, which means that C++ code doesn't create them with new or refer to them with pointers. Point and Size are good examples of these. If you aren't sure from the online help whether something is a value type or not, try compiling a line that uses it and the compiler will let you know if you've got it right.
  • The syntax for passing function pointers requires a & in C++ but not in C#. C# lets pointers-to-member functions be specified in a more concise syntax than C++.

Editing into C++

With that in mind, here are the steps to follow to edit the large mass of C# code you just pasted into your C++ source file so that it's valid C++:

  • Find the closing brace bracket at the end of the class definition (don't be tricked by the closing brace bracket at the end of the namespace block) and add a semicolon after it.
  • Change public class Form1 : System.Windows.Forms.Form to public __gc class Form1 : public System::Windows::Forms::Form
  • Change the block of lines that start using System to start using namespace System
  • Change all instances of . that separate namespaces such as System.Data to :: as in System::Data
  • Add these lines immediately before the block of using namespace statements:
    #using <System.dll>
    #using <System.Drawing.dll>
    #using <System.Windows.Forms.dll>
    #using <System.Data.dll>
    
  • Find fully qualified names like System.Windows.Forms.Button and change all the . characters to ::, or better still remove the fully qualified name, in this case just declaring a Button. (For Container, leave the fully qualified name to avoid compiler errors)
  • Change declarations of references, which would be solid objects in C++, to pointers. For example Button button1 becomes Button* button1.
  • Remove the word private or public from individual declarations and instead place a private: or public: on a line of its own before the set of declarations.
  • Remove the =null on the line that declares components, and add a line to the constructor to set components to NULL.
  • Edit-and-replace this. to this-> or nothing at all, since there aren't any name collisions in this example.
  • Remove any occurrences of the override keyword.
  • Remove any #region and #endregion pre-processor directives
  • Change the signature of the button1_Click() method to take pointers:
    void button1_Click(Object* sender, System::EventArgs* e)
  • Change the single line:
    Controls.AddRange(new System.Windows.Forms.Control[] { label1, button1});
    to the two lines
    Controls->Add(label1); 
    Controls->Add(button1);
  • In the Dispose method, change:
    base.Dispose( disposing );
    to
    Form::Dispose( disposing );
  • Find the lines that create a new Point object and take away the new keyword, so that the line reads, for example, label1->Location = Point(184, 96);
  • Do the same for the lines with Size, but call it by its full name, System::Drawing::Size, to avoid conflicts with the Size property of the form.
  • Change the line in the middle of InitializeComponent() that adds button1_Click() to the list of handlers for a click on button1 from
    this.button1.Click += new System.EventHandler(this.button1_Click);
    to
    button1->Click += new System::EventHandler(this, &Form1::button1_Click);
  • Take the single line in Form1::Main() and move it to _tmain(), editing it slightly so that it reads: Application::Run(new cs1::Form1()); (if you changed the namespace name from cs1, adjust this line.)
  • Remove Form1::Main() completely, it has no further work to do.
  • Just to show off, change the declaration of _tmain to int __stdcall WinMain() so that you won't get a telltale black box in the background when you run your WinForms application.

That's it! Try building and running it. If you get compiler errors, it's probably because you missed a . somewhere -- let the messages guide you to the place you need to fix. Here's what my code looks like:

// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"

#using <mscorlib.dll>
#include <tchar.h>

#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
using namespace System::Data;

namespace cs1
{
   /// <summary>
   /// Summary description for Form1.
   /// </summary>
public __gc class Form1 : public System::Windows::Forms::Form
   {
   private:
      Button* button1;
      Label* label1;
      /// <summary>
      /// Required designer variable.
      /// </summary>
      System::ComponentModel::Container* components;

   public:
      Form1()
      {
         //
         // Required for Windows Form Designer support
         //
         components = NULL;
         InitializeComponent();

         //
         // TODO: Add any constructor code after 
         // InitializeComponent call
         //
      }

      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
   protected:
      void Dispose( bool disposing )
      {
         if( disposing )
         {
            if (components != NULL) 
            {
               components->Dispose();
            }
         }
         Form::Dispose( disposing );
      }

      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
   private:
      void InitializeComponent()
      {
         button1 = new Button();
         label1 = new Label();
         SuspendLayout();
         // 
         // button1
         // 
         button1->Location = Point(48, 96);
         button1->Name = "button1";
         button1->TabIndex = 0;
         button1->Text = "Greet Me";
         button1->Click += new System::EventHandler(this,
                                    &Form1::button1_Click);
         // 
         // label1
         // 
         label1->Location = Point(184, 96);
         label1->Name = "label1";
         label1->TabIndex = 1;
         // 
         // Form1
         // 
         AutoScaleBaseSize =  System::Drawing::Size(5, 13);
         ClientSize =  System::Drawing::Size(292, 273);
         Controls->Add(label1);
         Controls->Add(button1);
         Name = "Form1";
         Text = "Form1";
         ResumeLayout(false);

      }


   private:
      void button1_Click(Object* sender, System::EventArgs* e)
      {
         label1->Text = "Hello from C++!";
      }
   };
}

// This is the entry point for this application
int __stdcall WinMain()
{
   Application::Run(new cs1::Form1());
    return 0;
}

What if you want to change your user interface later? Add another button and handler, or move one of the controls you already have? Well, you have two choices. Either you edit the C++ code you already have, or you go back to your starter C# app and edit your interface, then look at the code generated for you and do some careful copying and re-editing in your C++ code. You can see the way that the position, name, and text of each control is set in InitializeComponent(), and you can edit these lines at will to rearrange your user interface, or copy them to add more controls and handlers.

Well, that's all for now. I hope this column has shown you that C++ can do more than appears possible at first glance, and demonstrated some syntax differences between C# and C++. In future columns I'll talk more about managed types and value types, and some of the other subtle distinctions there wasn't space to discuss here.

About the Author

Kate Gregory is a founding partner of Gregory Consulting Limited (www.gregcons.com). In January 2002, she was appointed MSDN Regional Director for Toronto, Canada. Her experience with C++ stretches back to before Visual C++ existed. She is a well-known speaker and lecturer at colleges and Microsoft events on subjects such as .NET, Visual Studio, XML, UML, C++, Java, and the Internet. Kate and her colleagues at Gregory Consulting specialize in combining software develoment with Web site development to create active sites. They build quality custom and off-the-shelf software components for Web pages and other applications. Kate is the author of numerous books for Que, including Special Edition Using Visual C++ .NET.

# # #






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel