HomeDigital EditionSearch Dotnet Cd
ASP.NET C# Certification Exams The CLI Data Access Editorials Extending .NET Fundamentals Interoperability Interviews Migrate Mobile .NET Mono .NET Interface Object-Oriented Programming Open Source Optimization Product/Book Reviews Security Source Code UML Visual Studio .NET

In the early '90s, many companies invested in traditional client/server architectures by building fat-client applications with rich graphics that offloaded legacy-system processing time.

Visual C++ programmers have a long history of developing GUI (graphical user interface) applications for the Windows platform. For many of us, this history began in the early days of Windows 2.0 and 3.0. The only way to program GUI Windows applications back then was to use the C programming language to access the Windows application programming interface (API). Our guide through this territory was Charles Petzold's Programming Windows, which showed us how to write 175 lines of C code to define a plain window and create it!

Over the years, a variety of abstractions have been placed over this API for UI programming, with varying degrees of usefulness. In the C++ world, Visual C++ initially offered Microsoft Foundation Classes (MFC) based on inheritance, which had a lot of power in many areas but were lacking in others, as well as being complex for the average developer. MFC, although popular, is really a thin wrapper over the Win32 API that doesn't provide a lot of abstraction. Visual Basic offered a programming model based on events and forms coupled with a visual RAD capability, simplifying UI programming for the masses, but rendering itself extremely inflexible for nontrivial or "large" tasks. We C++ programmers tended to view the VB model as a "dumbing down" anyhow.

The visual editing and layout capabilities were impressive, but the lack of explicit control and power were quite frustrating. Typically, the first 90% of a real-world VB application was easy, but the last 10% was hell. Many other frameworks, such as WTL (Wrapper Template Language), were created to provide the basic "plumbing" or template for a Windows UI application.

The problem is that all of these abstractions offered vastly different programming models. A developer skilled in the use of one tool often encountered a great deal of grief when switching to another. Frequently, projects used more than one framework. Moreover, this type of programming was still very tedious and error-prone, particularly because developers still had to go down to the Windows API for some tasks, especially in Visual Basic development. Perhaps it was time for something that combined the visual rapid application development (RAD) of VB with the power of C++.

That something came in the summer of 2000, with the introduction of the Windows Forms class library, itself a part of the impressive .NET Framework. Much has been written about the clear benefits in developer productivity and efficiency that come with developing managed applications with the .NET Framework.

Windows Forms are a brand new managed platform that enables developers to build rich user interfaces for Windows desktop applications in managed languages like C#, MC++, and VB.NET. Because Windows Forms are part of the .NET Framework itself, they can leverage much of the technology in the framework, including the managed execution environment, the common type system (CTS), the common application environment, and OO principles.

Managed C++ has been a first-class managed language since the early days of the .NET Framework. The design of Managed C++ is quite impressive. Since C++ predated the CLR and managed code, the Managed C++ team faced impressive challenges in enabling C++, an existing and very popular computer language, to emit managed IL, even with existing native C++ code. Their solution was Managed Extensions for C++. Perhaps the most impressive feat of this technology is IJW or "It Just Works," which allows to a large extent, recompilation and running of the code as managed code. The problem, for those of us choosing to use the Managed Extensions for C++ or MC++, has been the lack of Windows Forms Designer support in the first shipping version of Visual Studio .NET. Developers choosing to use MC++ had to develop Windows Forms applications by hand, without the obvious visual layout and ease of the VS.NET visual Windows Forms Designer. In this article, I will show you how, with Visual C++ .NET 2003, Microsoft has provided the same benefits to Managed C++ programmers that had previously been available only to Visual C# .NET and VB.NET programmers, namely Windows Forms Designer support. In addition, I will walk you through the basics of creating a Managed C++ Windows Form.

This article assumes that you are familiar with the basics of Windows Forms from the C# perspective, and know the basics of Managed C++ programming. Also, please note that this article was written prior to the final release of Visual Studio .NET 2003 and there may be slight changes, although this appears unlikely at the time of this writing.

The Windows Forms Designer in VS.NET 2003
The Windows Forms Designer is a Visual Studio feature that enables developers to lay out and design user interfaces based on Windows Forms classes in the .NET Framework. In VS.NET 2002, only Visual C# and Visual Basic were supported by this feature, which generates application code in those languages. In VS.NET 2003, the Windows Forms Designer supports Visual C++ by also generating Managed C++ code via the new Managed C++ CodeDOM. In addition to the Windows Forms Designer, Visual Studio includes the Controls Designer, the Components Designer, and the XML Schema Designer.

What does it take to have Managed C++ support in the Forms Designer? Well, it turns out that there's another piece of .NET technology that the forms designer depends on. The designer needs to generate code for all the components that live on the form(s), and also needs to parse code as changes are made to the UI. The .NET Framework technology for this is the CodeDom, which lives in the System::CodeDom and System::CodeDom::Compiler namespaces. The CodeDom is a set of classes for representing most computer language structures, but in a language-independent manner. Each language-specific CodeProvider is then tasked with dealing with that language's nuances. The CodeDom is extremely flexible and powerful.

In this context, the CodeDom has code generator implementations in the Microsoft::CSharp and Microsoft::VisualBasic namespaces. The good news is that Managed C++ now has a CodeDom parser, named MCppCodeDomParser.dll, and a CodeDomProvider, MCppCodeDomProvider.dll. As of this writing, these two DLLs were not located in the same place as the C# and VB versions, but in C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\PublicAssemblies.

The designer uses the CodeDomProvider to generate Managed C++ code. Let's look at an example.

Creating a Managed C++ Windows Form Project
Microsoft Visual C++ .NET 2003 now includes the ability to create Windows Forms Applications. This is reflected in the Visual C++ New Project dialog as shown in Figure 1.

Figure 1

The first thing that you will notice after running the New Project wizard for an MC++ Windows Forms application is that the designer operates on and generates code in the header file (.h). The wizard also generates a .cpp file, but as you add UI elements and event handlers, the forms designer will place the code in the header file. This may seem like an odd choice, but you must remember two things. First, the C++ designers had to fit within the existing architecture of VS.NET and its support for "single-file" languages like C# and VB.NET. Second, C++, as a language, is all about separating implementation and definition. It's too early to speculate, but there are some indications that this may change in a future version.

The wizard does generate the code for the WinMain() function in the .cpp file. We will look at that code shortly. First, let's look at the code generated by the designer in the header file.

The Managed C++ Implementation of a Windows Form
Let's examine the code in Listing 1. For those who have looked at Windows Forms code generated by the C# or VB.NET wizards, this code looks very similar. The class is contained within a namespace, ManagedCPPWinForm, and using the namespace declarations at the top does the same thing as using directives in C#; namely bringing the type names in the namespaces into the current scope. Of particular importance is the System::Windows:: Forms namespace, which contains almost all of the functionality of Windows Forms, such as forms, containers, and controls.

In every Windows Forms application, you will have a class derived from System::Windows::Forms::Form.

public __gc class Form1 : public System::Windows::Forms::Form

The Form class is derived from Control, which is derived from Component. A form is both a component and a container of components. It is also a container of controls.

Examining the class declaration, notice that Form1 is a managed class signified by the __gc modifier, which means that this a class subject to garbage collection and its lifetime is controlled by the CLR. The instance of this class is the application's main window.

The Form class is the cornerstone of the application and provides rich functionality. As I have mentioned, a form is a container of components, which we see in the private member variable, components:

private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container * components;

The designer uses this variable in the InitializeComponent() method to build the form at runtime. All of the controls and properties that you set during design time are set at runtime in this method. Any time you change the form in Design Mode, the designer will update this method, as shown in Listing 2.

The Message Pump
The other important piece that is needed for every Windows Forms application is the class System::Windows::Forms::Application. In this class is a static method called Run that drives the Windows Forms application by providing a message pump. The message pump is not something you see. The .NET Framework abstracts it away so you don't need to worry about it. In Managed C++, the code for WinMain() looks like Listing 3.

A Window
This is enough code to display a working Windows Form on the desktop. When built and run, it produces a window similar to that shown in Figure 2.

Figure 2

Obviously, from here, there is much more that can be done. The developer can drag-and-drop controls from the toolbox and write code, but the basic idea here is that it is now possible to have visual editing capabilities with Managed C++.

Conclusion
I have taken you on a historical tour of C++ based GUI development, leading up to Windows Forms with Managed C++. In the first version of VS.NET, Managed C++ lacked the visual designers, leading to hardship for Managed C++ developers. As I have shown you in this article, Visual Studio .NET 2003 and Visual C++ .NET 2003 now provide visual designers and Managed C++ code generation, enabling RAD GUI development in Managed C++. Coupled with the power of Managed C++ itself to perform functions not available in other CLR languages, this is a significant and welcome addition. In a future article, I will go into detail about some of these unique abilities of Managed C++.

About The Author
Sam is a .NET consultant, author, and speaker who has been working with .NET since the alpha and currently works with future versions of the .NET Framework, as well as future Microsoft products. He is a coauthor of Wrox's Visual C++ .NET: A Primer for C++ Developers, and is currently at work on a .NET book for O'Reilly. Sam maintains a very popular Web site: www.samgentile.com. managedcode@attbi.com

	



Listing 1: The code generated by the Managed C++ Forms Designer.


#pragma once



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


    /// <summary> 
    /// Summary for Form1
    ///
    /// WARNING: If you change the name of this class, you will need to
	change the 
    ///          'Resource File Name' property for the managed resource
	compiler tool 
    ///          associated with all .resx files this class depends on.
	Otherwise,
    ///          the designers will not be able to interact properly with
	localized
    ///          resources associated with this form.
    /// </summary>
    public __gc class Form1 : public System::Windows::Forms::Form
    {    
    public:
        Form1(void)
        {
            InitializeComponent();
        }
  
    protected:
        void Dispose(Boolean disposing)
        {
            if (disposing && components)
            {
                components->Dispose();
            }
            __super::Dispose(disposing);
        }


    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container * components;


        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->components = new System::ComponentModel::Container();
            this->Size = System::Drawing::Size(300,300);
            this->Text = S"Form1";
        }    
    };
}



Listing 2: Updating InitializeComponent()

void InitializeComponent(void)
{
    this->components = new System::ComponentModel::Container();
    this->Size = System::Drawing::Size(300,300);
    this->Text = S"Form1";
}



Listing 3: WinMain()

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    System::Threading::Thread::CurrentThread->ApartmentState =
	System::Threading::ApartmentState::STA;
    Application::Run(new Form1());
    return 0;
}

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.

  E-mail: info@sys-con.com