How to: Migrating a CLR console Visual C++ project to Windows Forms#
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.