- Building an MFC Application
- Building a Managed .NET Framework Application
- Comparing the Differences
- Summary
- Q&A
- Workshop
Building a Managed .NET Framework Application
Switching gears to the .NET Framework and building the same type of application as a managed C++ application is a bit different, as you will see. The first step is the same: Select to build a new project from the main menu, only this time select Managed C++ Application as the type and name the application HelloNET.
Notice that you don't receive any wizard to ask what settings you would like to have in your application, as you did with the MFC application. The C++ .NET applications are generated with a script that builds a basic application framework that is a console "Hello World" application. One difference between Visual C++ .NET and the other .NET languages is that there is no form editor for Visual C++ .NET to edit Windows Forms, the basis of building user interfaces in .NET. Although it may seem daunting at first having to hand-code the user interface, you'll find that working with the .NET Framework Forms classes is rather intuitive.
Tip
If you want to learn C# also, you can actually use a dummy application in C# that does provide the Windows Form editor to build your forms and then port the code into VC++ .NET. You have to know how to do the porting, but it isn't that difficult with a little practiceand it saves time on designing your forms.
The next step is to declare a class that represents the form for the application. Select Project, Add Class from the main menu. In the list of available templates in the dialog that is displayed, select the Generic C++ Class template and click the Open button. Name the class CHelloNETForm and specify the base class Form, the .NET Framework's class found in the System::Windows::Forms namespace, which provides the Windows Form functionality. You may get an error message explaining that Visual Studio .NET cannot find the Form base class. Click Yes to continue adding the class. Performing the previous steps sets up a new file and skeleton code for your class. The next steps will transform your generic class into a managed C++ .NET class.
Click the Class View tab next to the Solution Explorer tab on the right side of the IDE window. Expand the project tree and locate the Classes item and expand that also. You should now see your CHelloNETForm class. Right-click the class and select Add, Add Variable from the context menu. You will now be presented with the Add Variable dialog. Set the access to protected, the variable type to Button*, and the variable name to m_pbtnMessage. Then click Finish. Add another Button* variable named m_pbtnDone and a Label* variable named m_pstMessage.
The variables you just added are .NET Framework classes within the Forms namespace. Controls, however, need to have a container object to hold them. Add another variable of type System::ComponentModel::Container* with the name m_pComponents and the same protected access level.
Now that you've added the member variables, its time to add some member functions. Right-click the CHelloNETForm class again, but this time select Add, Add Function. Enter void as the return type, InitForm as the function name, and an access level of protected. Click Finish to close the dialog.
The last step to finish the design of the class is to add the necessary elements that are not supported by wizards within the IDE. Using Listing 3.1 as a guide, add the appropriate using statements and add the __gc keyword immediately preceding the class keyword. This indicates to the compiler that the class is managed by the .NET Framework and its memory manager.
When you are finished, you're HelloNETForm.h file should look similar to Listing 3.1.
Listing 3.1 Transforming a Generic C++ class into Managed Code
1: #pragma once 2: 3: #using <mscorlib.dll> 4: 5: #using <System.DLL> 6: #using <System.Drawing.DLL> 7: #using <System.Windows.Forms.DLL> 8: 9: using namespace System; 10: using namespace System::Windows::Forms; 11: 12: __gc class CHelloNETForm : public Form 13: { 14: public: 15: CHelloNETForm(void); 16: ~CHelloNETForm(void); 17: protected: 18: Button* m_pbtnMessage; 19: Button* m_pbtnDone; 20: Label* m_pstMessage; 21: System::ComponentModel::Container* m_pComponents; 22: void InitForm(); 23: };
Now it's time to fill in the functions you just created. Refer to Listing 3.2 as you read through this section. To begin with, try and compile your project. One thing you'll notice is that the compiler complains that NULL is undefined. One great addition to Visual C++ .NET is that when you're adding member variables to a class like we did earlier, the generated code also includes class initializers for these variables. In this case, because we declared pointers, the generated code set these variables to NULL. However, it didn't add the appropriate #include statement. To fix this problem, include the header file stdlib.h at the top of the HelloNETForm.cpp file. Your program should now compile with zero errors and zero warnings.
Begin by filling in the constructor code. Because the member variables you added are simply pointers, you need to create the objects before you can use them. Therefore, create the form control container member variable (m_pComponents) by using the C++ keyword new. The remaining line in the constructor calls the InitForm function.
In the InitForm() function, create the three controls, one by one, and set the properties appropriately. After all the controls are created, they are added to the form with the Form::Controls->Add() method. The order in which the controls are added has an effect on the tab order if the tab order isn't specified for the controls. In this case, it is specified and therefore doesn't matter.
Listing 3.2 Creating the Form
1: #include "stdafx.h" 2: #include "hellonetform.h" 3: #include <stdlib.h> 4: 5: #using <mscorlib.dll> 6: CHelloNETForm::CHelloNETForm(void) 7: : m_pbtnMessage(NULL) 8: , m_pbtnDone(NULL) 9: , m_pstMessage(NULL) 10: , m_pComponents(NULL) 11: { 12: m_pComponents = new System::ComponentModel::Container(); 13: 14: // Initialize the Form 15: InitForm(); 16: } 17: 18: CHelloNETForm::~CHelloNETForm() 19: { 20: } 21: 22: void CHelloNETForm::InitForm() 23: { 24: 25: // Allocate the controls 26: m_pbtnMessage = new Button(); 27: m_pbtnDone = new Button(); 28: m_pstMessage = new Label(); 29: 30: SuspendLayout(); 31: 32: // Initialize all control properties 33: // 34: // Message Button 35: // 36: m_pbtnMessage->Location = System::Drawing::Point(240, 8); 37: m_pbtnMessage->Name = "Message"; 38: m_pbtnMessage->TabIndex = 0; 39: m_pbtnMessage->Text = "Message"; 40: m_pbtnMessage->add_Click( 41: new System::EventHandler( this, &CHelloNETForm::OnMessageClick ) ); 42: 43: // 44: // Done Button 45: // 46: m_pbtnDone->Location = System::Drawing::Point(240, 40); 47: m_pbtnDone->Name = "Done"; 48: m_pbtnDone->TabIndex = 1; 49: m_pbtnDone->Text = "Done"; 50: m_pbtnDone->add_Click( 51 new System::EventHandler( this, &CHelloNETForm::OnDoneClick ) ); 52: // 53: // Message Label 54: // 55: m_pstMessage->Location = System::Drawing::Point(8, 8); 56: m_pstMessage->Name = "Label"; 57: m_pstMessage->Size = System::Drawing::Size(192, 40); 58: m_pstMessage->TabIndex = 2; 59: m_pstMessage->Text = ""; 60: 61: // Set form properties and add controls to form 62: // 63: // Form1 64: // 65: AutoScaleBaseSize = System::Drawing::Size(5, 13); 66: ClientSize = System::Drawing::Size(322, 87); 67: Controls->Add( m_pstMessage ); 68: Controls->Add( m_pbtnDone ); 69: Controls->Add( m_pbtnMessage ); 70: 71: FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog; 72: Name = "HelloNET"; 73: Text = "HelloNET"; 74: 75: ResumeLayout(false); 76: }
In order for your form to respond to user events, you'll need to capture the button click events. Events that were previously handled with the MFC message map are handled quite differently in the .NET Framework. Events are handled by delegates within your class. A delegate is quite similar to a C/C++ function pointer. You assign delegates to handle object events with the following statement:
m_pbtnMessage->add_Click( new System::EventHandler( this, &CHelloNETForm::OnMessageClick ) );
Every time the Message button is clicked, the CHelloNETForm::OnMessageClick() method is called. In your project, you will add two event handlers to the two buttons.
Event handlers must have a specific set of parameters, much in the same way they did for MFC message map handlers. For most events, pointers to a generic Object and an EventArgs object are passed as parameters. The generic Object pointer is a pointer to the object that caused the event, whereas the EventArgs object contains information specific to the event. Following the instructions given earlier, add two member functions. The first function is named OnMessageClick, and the second function is named OnDoneClick. Both functions have a void return type, protected access level, and two parameters: Object* source and EventArgs* e. Listing 3.3 shows the final version of the HelloNETForm.h file.
Listing 3.3 Adding Event Handler Declarations
1: #pragma once 2: 3: #using <mscorlib.dll> 4: 5: #using <System.DLL> 6: #using <System.Drawing.DLL> 7: #using <System.Windows.Forms.DLL> 8: 9: using namespace System; 10: using namespace System::Windows::Forms; 11: 12: __gc class CHelloNETForm : public Form 13: { 14: public: 15: CHelloNETForm(void); 16: ~CHelloNETForm(void); 17: protected: 18: Button* m_pbtnMessage; 19: Button* m_pbtnDone; 20: Label* m_pstMessage; 21: System::ComponentModel::Container* m_pComponents; 22: void InitForm(); 23: void OnMessageClick( Object* source, EventArgs* e); 24: void OnDoneClick( Object* source, EventArgs* e); 25: };
Now open the HelloNETForm.cpp file. The two functions you just added will be at the bottom of the file. In OnMessageClick, set the m_pstMessage Text property to "Hello from the .NET World." For the OnDoneClick function, call the function Close, which shuts down the application. The two functions should appear similar to the following:
1: void CHelloNETForm::OnMessageClick( Object* source, EventArgs* e ) 2: { 3: m_pstMessage->Text = "Hello from the .NET World."; 4: } 5: 6: void CHelloNETForm::OnDoneClick( Object* source, EventArgs* e ) 7: { 8: Close(); 9: }
The final change to the application is to have the main() function create and run the new Windows Form class. Make the changes shown in the following code segment:
#include "helloNETform.h" int _tmain(void) { Application::Run(new CHelloNETForm()); return 0; }
With those final additions, the application is ready to compile and run. This is the same as with the MFC application. Simply press the F5 key or select the Debug, Start menu command. The resulting Visual C++ .NET application should have the same appearance as the MFC application created earlier.