在 Windows 编程环境下,编写一个命令行程序依然是简单的,但它并不是最适合这个环境的。 Windows 根本上就是个基于图形化操作的系统,所以即使你是用 GNU 的 gcc 编译器 (MinGW),你依然会得到 windows.h 的支持。
在 Windows 环境中,C 语言并不是图形化开发的最理想工具,VB 和 C# 相比而言更容易使用。但是,作为现代程序员,我们知道,微软很强大,却从来没有独占江山,C 语言的地位并没有因以上两种专属语言的方便优势而降低,仍然是最简洁、应用最广泛的语言。而且由于微软的其它建筑都是以 C 语言为基础的,所以 C 语言的的使用虽然不“方便”(许多 C# 中可以使用绘图工具完成的操作在 C 要通过文字完成),却具有最佳的灵活性。最重要的一点,迄今为止,并没有其他语言在效率上高于 C 。
C 语言可视化程序基本结构
下面是一个空的可视化程序框架:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
return 0;
}
这个不是一个完整的程序,因为他不具备任何功能,要想使用它,我们必须在它适当的地方填充一些内容。
首先,程序的入口不再是 main() 函数,而是 WinMain() 。所以,程序的运行过程就是 WinMain() 函数的运行过程。在 WinMain() 函数里,我们要做以下几点:
1. 构造窗体结构;
2. 显示窗口;
3. 监听和处理窗口事件。
也许你会注意到 WinMain() 函数的参数列表当中有许多不明类型的参数,显得十分可怕。既然可怕就暂时不去管它,到用的时候我们再解释。
除了 WinMain() 函数,WndProc() 函数也是必不可少的处理函数,这个函数规定了你的窗体在遇到那些事情的时候该怎么办。这个函数里一般使用一个 switch 结构,讨论其第二个参数 (unsigned int, UINT) 的值,是一个整数,不同的数字表示不同的事件,对于每一种事件我们都对它做出相应的反应,这里就类似于 VB 和 C# 的双击控件设定事件的过程。当然,WndProc() 是用来处理窗体的触发事件的函数,别的控件,比如按钮,会有它独立的处理函数。
但是,对于一个控件(比如一个按钮),我们可以设置的事件可能有多种,比如左击、右击等,我们未必规定了每一种事件(实际上,我们通常只规定其中的一个或很少一部分),剩下的事件交给一个叫做 DefWindowProc() 的函数完成,这个函数的参数列表与 WndProc() 完全一致,返回值可以直接作 WndProc() 的返回值,所以一般 WndProc() 函数的返回值就是一个 DefWindowProc() 函数。
计算机是一个过程处理中心,它并不是一个被动的机器,而是一个主动的机器,但由于可视化的应用程序呈现的是一个被动的操作界面(比如你点一个按钮,才发生了一个事件),这种模式叫“触发”,启动触发事件的机关叫“触发器”。计算机作为主动的机器,是通过不间断的“监听”来完成触发的模拟,“监听”就是不断地检查窗体有没有被“触”(比如不断的检查某个按钮那块区域是否被点击了),一旦发现了所监听的事件,就立刻调用相关过程作出反应,这就是触发模拟的基本原理。所以,“处理窗口事件”就是不断地循环检查并作出反应,直到程序结束的过程。但由于图形操作面临两个事件同时被触发的问题,这就是多线程问题,这一点在 Windows 现有的机制下已经被巧妙的解决,我们所使用的函数中已经蕴含了相关的方法,只是我们看不见。
下面转载一个实例(来源:https://www.cnblogs.com/mr-wid/archive/2012/10/08/2715673.html),供大家参考:
#include <windows.h>
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); //声明用来处理消息的函数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow ) {
static TCHAR szAppName[] = TEXT("MyWindow") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
//以下为窗口类对象wndclass的属性
wndclass.style = CS_HREDRAW | CS_VREDRAW ; //窗口样式
wndclass.lpszClassName = szAppName ; //窗口类名
wndclass.lpszMenuName = NULL ; //窗口菜单:无
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ; //窗口背景颜色
wndclass.lpfnWndProc = WndProc ; //窗口处理函数
wndclass.cbWndExtra = 0 ; //窗口实例扩展:无
wndclass.cbClsExtra = 0 ; //窗口类扩展:无
wndclass.hInstance = hInstance ; //窗口实例句柄
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ; //窗口最小化图标:使用缺省图标
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; //窗口采用箭头光标
if( !RegisterClass( &wndclass ) ) {
//注册窗口类, 如果注册失败弹出错误提示
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ;
return 0 ;
}
hwnd = CreateWindow( //创建窗口
szAppName, //窗口类名
TEXT("My Application Window"),//窗口标题
WS_OVERLAPPEDWINDOW, //窗口的风格
CW_USEDEFAULT, //窗口初始显示位置x:使用缺省值
CW_USEDEFAULT, //窗口初始显示位置y:使用缺省值
CW_USEDEFAULT, //窗口的宽度:使用缺省值
CW_USEDEFAULT, //窗口的高度:使用缺省值
NULL, //父窗口:无
NULL, //子菜单:无
hInstance, //该窗口应用程序的实例句柄
NULL //
) ;
ShowWindow(hwnd, iCmdShow) ; //显示窗口
UpdateWindow(hwnd) ; //更新窗口
while(GetMessage(&msg, NULL, 0, 0)) { //从消息队列中获取消息
TranslateMessage(&msg); //将虚拟键消息转换为字符消息
DispatchMessage(&msg); //分发到回调函数(过程函数)
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc ; //设备环境句柄
PAINTSTRUCT ps ; //绘制结构
RECT rect; //矩形结构
switch(message) { //处理得到的消息
case WM_CREATE: //窗口创建完成时发来的消息
MessageBox( hwnd, TEXT("Created Window!"), TEXT("My window"), MB_OK | MB_ICONINFORMATION ) ;
return 0;
case WM_PAINT: //处理窗口区域无效时发来的消息
hdc = BeginPaint( hwnd, &ps ) ;
GetClientRect( hwnd, &rect ) ;
DrawText( hdc, TEXT( "Hello, My window!" ), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
EndPaint( hwnd, &ps ) ;
return 0 ;
case WM_LBUTTONDOWN: //处理鼠标左键被按下的消息
MessageBox( hwnd, TEXT("Left Clicked."), TEXT("Click Event"), MB_OK | MB_ICONINFORMATION ) ;
return 0;
case WM_DESTROY: //处理窗口关闭时的消息
MessageBox( hwnd, TEXT("End!"), TEXT("END"), MB_OK | MB_ICONINFORMATION ) ;
PostQuitMessage( 0 ) ;
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);//DefWindowProc处理我们自定义的消息处理函数没有处理到的消息
}