最近有几位朋友找我,VS 2012的Express版本,在C++/CLR项目中只能编写控制台应用程序,不支持WinForm啊,怎么办?
于是,有人就尝试在CLR的控制台应用程序中编写Windows Forms应用程序,理论上讲嘛,是可以的,不信?你看看下面的代码。
// 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事件处理代码。
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头文件。
看看,入口点函数如下:
#include <Windows.h> int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { // .......... return 0; }
这里为什么我用wWinMain而不是WinMain呢?我们来看看WinBase.h中的定义吧。
我们的程序是中文的,应属于Unicode的,所以,最好使用wWinMain函数,它是一个宏,无论如何定义,它最终都是指向WinMain函数。
刚才我们做了一个MainFom窗体,我们要把它所在的头文件包含进来。
#include <Windows.h> #include "MainForm.h"
接着我们在入口点中显示主窗体。完整的代码如下:
#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都换了,这是走向成熟的标志。所以,我建议大家,学到的知识要灵活去应用,不必要为了使用而使用某个语言,最重要的是高效快捷地解决问题就行了,有了技术还得加上技巧的配合才能发挥作用。