Note: Windows Forms programming in new development is discouraged by Microsoft at this point as Microsoft wants to make full use of hardware accelerated drawing instead of using the CPU-intensive GDI. But maintaining old Windows Forms code in Visual C++ 2012 is still supported, GDI isn’t going anywhere anytime soon.
Visual C++ 2012 removed the Windows Forms project template and I see people scramble to find ways to create a Windows Forms project. There is a walkaround that’s been around for years, that is, to convert a CLR console application to a Windows one, then add forms related code to the project.
The basic steps are listed at http://support.microsoft.com/kb/317433, conveniently named “How to suppress the console window for a managed extensions to Visual C++ Windows Forms application“. Yes, the need to convert a C++ console application to windows forms is that old, back all the way back in the managed extensions for C++ days.
So what I need to do to add Windows Forms support to a C++/CLI console application? Of course the System.Windows.Forms.dll reference is missing in a new console application, so I need to reference it:
- In code:
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
using namespace System::Windows::Forms;
- Or In IDE:
- Select the project in Solution Explorer
- On the Project menu or the context menu of the project node, select Properties
- In the Property Pages dialog box, expand the Common Properties node, select Framework and References, and then click Add New Reference.
- Find and add System.Windows.Forms in the list of available references.
In reality the Windows Forms Designer generates a lot of layout code that uses System.Drawing types like Point and Size, so I need to repeat the steps for System.Drawing.
Next the console window needs to be suppressed. The C++/CLI console project template in fact does not specify an entry point, so compiler guesses because a main function exists, the project is a console application. A Windows Forma application’s entry point has the same signature with the main function, therefore the /subsystem setting of the project needs to be changed to Windows:
- Go back to the project’s Property Pages dialog box.
- Click the Linker folder on the type.
- Click the System property page.
- Change the SubSystem property to Windows.
Ready? Not yet. The compiler is now trying to find a WinMain function, and throws LNK2028 and LNK2019 when it can’t find the entry point, which of course isn’t there. I am not interested in writing one as I prefer to keep the nice args command line parameter of an array<String^>^ type , so I need to tell the compiler my entry point function is still main:
- Go back to the the Linker folder.
- Click the Advanced property page.
- Change the Entry Point property to main.
We are almost here. Windows Forms needs an STA thread, so I have to add [STAThreadAttribute] to the main function:
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
….. // wait did I add anything here? I guess not yet
Here you go, a Windows Forms application that does nothing interesting. Mmm, to make it a little more visual, I create a new Windows Form class named Form1 and run it in the main function:
//before main function
#include “Form1.h”
using namespace ProjectName;
//in the main function
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
Yada! I have a Windows Forms application running now.
Leave a Reply