最近有幾位朋友找我,VS 2012的Express版本,在C++/CLR項目中只能編寫控制台應用程序,不支持WinForm啊,怎麼辦? 於是,有人就嘗試在CLR的控制台應用程序中編寫Windows Forms應用程序,理論上講嘛,是可以的,不信?你看看下面的代碼。 [cpp] // C++ #include "stdafx.h" using namespace System; [STAThreadAttribute] int main(array<System::String ^> ^args) { System::Windows::Forms::Form^ mainForm = gcnew System::Windows::Forms::Form(); // 窗體大小 mainForm->Height=300; mainForm->Width =500; // 窗體標題 mainForm -> Text = L"我的主窗口"; // 窗口的初始位置 mainForm -> StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; // 開始在窗口上的主消息循環並顯示窗口 System::Windows::Forms::Application::Run(mainForm); return 0; } // C++ #include "stdafx.h" using namespace System; [STAThreadAttribute] int main(array<System::String ^> ^args) { System::Windows::Forms::Form^ mainForm = gcnew System::Windows::Forms::Form(); // 窗體大小 mainForm->Height=300; mainForm->Width =500; // 窗體標題 mainForm -> Text = L"我的主窗口"; // 窗口的初始位置 mainForm -> StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen; // 開始在窗口上的主消息循環並顯示窗口 System::Windows::Forms::Application::Run(mainForm); return 0; } 可以說這段代碼是沒有問題的,運行一下就知道了。 程序是運行起來了,但讓很多人不高興,為啥?你認真瞧瞧,它總是會伴隨著一個DOS窗口啟動,這不太像WinForm,至少要不讓那個DOS窗口跑出來。 是啊,這確實有點怪怪的,呵呵。 由於Express版本免費,而且具備了VS的核心功能,對於很多學生,個人或中小型項目來說是完全勝任的,我也一直在用這個版本。其實VS 2012 Express for Desktop在WinForm應用中支持VB和C#,但在C++的CLR項目模板中沒有,而上面的方法又解決不了那個DOS窗口,咋辦呢? 一時興起,我在網上搜了一下相關論壇,確實不僅那幾位朋友,看來想解決這問題的人還不少呢。 我是有方法解決,只是不知道算不算是最好的方法,反正只代表我個人想法,今天,我想在博客上分享一下,如果你想到更好的方法,你也不妨向大家分享一下。 雖然在C++的項目模板中看不到WinForm,但有一個應用模板你一定不陌生——Win 32 應用程序,對吧,我就是拿它來開刀的。 為什麼會顯示窗口呢?因為入口點是main,大家應該記得,Windows窗體應用程序的入口點是WinMain,是的,這樣一說,你可以已經猜到我的解決方法了。 原理:在Win 32應用程序中編寫托管代碼,不管怎麼說,其實WinForm就是對Win32的一種封裝罷了。 好了,我就不多扯了,不然有人說是廢話,接下來我們開始吧。 啟動Visual Studio 2012 Express for Desktop,新建項目,在項目模板中找到Visual C++/Win32 / Win32 項目。 輸入項目名字,確定。 隨後會彈出一個向導,點擊下一步。 在應用程序類型中選擇“Windows應用程序”,在附加選項中勾選“空項目”,然後點擊完成。 好了,這時候,一個空的Win32 項目已經建好了,不過,不要急著寫代碼,因為,我們要做一些設置才能編寫托管代碼。 (1)鼠標右擊項目節點,從彈出的快捷菜單中選擇【屬性】。 (2)在項目屬性窗口中,依次找到“配置屬性- 常觀”,在右邊的屬性設置網格中找到“公共語言運行時支持”,選擇“公共語言運行時支持(/clr)”。 記得為debug和release模式也設置一遍。 (3)展開“通用屬性 - 框架和引用”,添加可能會用到的程序集的引用。 單擊“確定”按鈕,關閉屬性窗口。這樣,就配置好了,下面就可以編寫托管代碼了。 在解決方案資源管理器中,右擊項目節點,從彈出的菜單中選擇【添加】-【新建項】,在彈出的窗口中,找到UI節點,在右邊窗格中選擇“Windows窗體”。 輸入名字後單擊確定,這時候,我們看到灰常熟悉的窗口設計器,我們可在上面扔控件。 雙擊按鈕,編寫它的Click事件處理代碼。 [cpp] private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { System::Windows::Forms::MessageBox::Show( L"你選擇的日期是:" + this->dateTimePicker1->Value.ToString(L"yyyy年MM月dd日"), L"提示信息", System::Windows::Forms::MessageBoxButtons::OK, System::Windows::Forms::MessageBoxIcon::Information); } private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { System::Windows::Forms::MessageBox::Show( L"你選擇的日期是:" + this->dateTimePicker1->Value.ToString(L"yyyy年MM月dd日"), L"提示信息", System::Windows::Forms::MessageBoxButtons::OK, System::Windows::Forms::MessageBoxIcon::Information); } 到了現在,窗口做好了,不過啊,還不能運行,我們還有關鍵的一步,對,入口點。 右擊項目節點,從彈出來的菜單中選擇【添加】-【新建項】,在 代碼 節點下選擇C++文件 *.cpp,隨便給個名字,確定,我們在這裡面寫入口點函數。 注意了,我們要的是Windows應用程序,不是DOS控制台,所以我們寫的是WinMain函數。首先,要包含Windows.h頭文件。 看看,入口點函數如下: [cpp] #include <Windows.h> int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { // .......... return 0; } #include <Windows.h> int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { // .......... return 0; } 這裡為什麼我用wWinMain而不是WinMain呢?我們來看看WinBase.h中的定義吧。 我們的程序是中文的,應屬於Unicode的,所以,最好使用wWinMain函數,它是一個宏,無論如何定義,它最終都是指向WinMain函數。 剛才我們做了一個MainFom窗體,我們要把它所在的頭文件包含進來。 [cpp] #include <Windows.h> #include "MainForm.h" #include <Windows.h> #include "MainForm.h" 接著我們在入口點中顯示主窗體。完整的代碼如下: [cpp] #include <Windows.h> #include "MainForm.h" using namespace System::Windows::Forms; int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { Application::Run(gcnew MyWindowsFormApp::MainForm()); return 0; } #include <Windows.h> #include "MainForm.h" using namespace System::Windows::Forms; int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { Application::Run(gcnew MyWindowsFormApp::MainForm()); return 0; } 注意,創建新實例的時候,在托管C++中要用gcnew。 現在,運行一下,是不是沒有了DOS窗口了。 好了,看不到DOS窗口了,這樣就解決問題了。 一些建議: 我們不應該為了用某種語言而用某種語言,WinForm其實也是封裝了Win32控件的,所以,有時候應考慮用VB.NET或C#,至少可以提高開發效率,而UI布局也方便了很多,C++可以用於編寫一些類庫之類的。 在.NET 4之後,許多類庫被重寫,性能有了本質提升,你看看.NET 4.0 連Logo都換了,這是走向成熟的標志。所以,我建議大家,學到的知識要靈活去應用,不必要為了使用而使用某個語言,最重要的是高效快捷地解決問題就行了,有了技術還得加上技巧的配合才能發揮作用。