最近有幾位朋友找我,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都換了,這是走向成熟的標志。所以,我建議大家,學到的知識要靈活去應用,不必要為了使用而使用某個語言,最重要的是高效快捷地解決問題就行了,有了技術還得加上技巧的配合才能發揮作用。