本系列博文几乎没有难啃的“专业术语”,尽可能让读者可以看明白文章所述内容,是本系列博文的核心宗旨之一。(因为本人也是因为项目须要,因此才来查阅相关资料,文中出现的错误欢迎指出,共同进步!谢谢!)windows
读本系列博文的读者必须具有如下的知识储备:api
窗口在 Windows 中指一个矩形区域,通常状况下这个区域是用户与应用程序交互的枢纽;上一小节使用 MessageBox 建立的简单窗口也是与用户交互的一个窗口,该窗口的功能有限,只可以简单的展现一些想要表达的信息,想建立一个能表达更多信息的窗口,可使用 CreateWindow 函数建立。数据结构
建立 Windows 桌面应用程序须要 windows.h,在头部引入 windows.h 头文件。app
#include <windows.h>
复制代码
在C语言中,每一个C语言程序都有一个入口函数,在Windows桌面程序中,这个入口函数是 WinMain ,具体声明以下:函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
复制代码
在程序中,紧接着在头部文件后,咱们使用 WinMain做为程序的入口函数:布局
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {}
复制代码
写好入口函数后,必需要使用 RegisterClassEx 注册一个新的窗口类型,再使用 CreateWindow 进行建立。post
在注册新窗口前,咱们可使用一个 WNDCLASSEX 结构用来描述建立的Windows,这是窗口类;微软开发中心对WNDCLASSEXA的描述:“Contains window class information. It is used with the RegisterClassEx and GetClassInfoEx functions.”;WNDCLASSEXA 是包含窗口信息的结构。语法以下:学习
typedef struct tagWNDCLASSEXA {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;
复制代码
结构成员:字体
sizeof(WNDCLASSEX)
CS_HREDRAW | CS_VREDRAW
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
代码实现以下:ui
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
复制代码
——————————————————————————————————
值参考:
LoadCursor 返回类型为 HCURSOR:的语法以下:
HCURSOR LoadCursorW( HINSTANCE hInstance, LPCWSTR lpCursorName );
复制代码
参数说明:
在微软的参考文档中说明,lpCursorName 的可设置为如下值:
lpfnWndProc 为接收窗口处理的指针,使用 WndProc 处理应用程序在发生事件时从 Windows 接收的消息。在微软的文档中写道:“WndProc 是每一个 Windows 桌面应用程序必须的窗口过程功能。 此函数一般命名为WndProc,但您能够为所欲为地命名它。 例如,若是用户在应用程序中选择"肯定"按钮,Windows 会向您发送消息,您能够在WndProc函数内编写代码,执行任何适当的操做。 这称为处理事件。 您只处理与应用程序相关的事件。WndProc 具备如下语法”;以下:。
LRESULT CALLBACK WndProc( _In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam );
复制代码
那咱们在程序中声明也如此声明,那么定义以下(使用微软文档示例):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主页:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
复制代码
在以上 WndProc 的实现中,使用了 switch 语句,在 switch 中判断了 WM_PAINT 消息;WM_PAINT 消息为绘制主窗体,在文档中写到:
要处理的一条重要信息是WM_PAINT消息。 当必须更新其显示WM_PAINT窗口的一部分时,应用程序将接收消息。 当用户在窗口前面移动窗口,而后再次将其移开时,可能会发生此事件。 您的应用程序不知道这些事件什么时候发生。 只有 Windows 知道,所以它会经过消息WM_PAINT通知你的应用。 首次显示窗口时,必须更新全部窗口。 要处理 WM_PAINT 消息,首先应调用 BeginPaint,而后处理全部的逻辑以在窗口中布局文本、按钮和其余控件,而后调用 EndPaint。
——————————————————————————————————
BeginPaint 的语法为:
HDC BeginPaint( HWND hWnd, LPPAINTSTRUCT lpPaint );
复制代码
参数说明:
——————————————————————————————————
该调用EndPaint函数标记指定窗口画的结束。每次调用BeginPaint函数都须要此函数,可是仅在绘制完成以后。
语法:
BOOL EndPaint( HWND hWnd, const PAINTSTRUCT *lpPaint );
复制代码
参数说明:
——————————————————————————————————
向系统指示线程已请求终止(退出)。一般用于响应WM_DESTROY消息。
语法:
void PostQuitMessage( int nExitCode );
复制代码
参数说明:
——————————————————————————————————
调用默认窗口过程觉得应用程序未处理的任何窗口消息提供默认处理。此功能确保处理全部消息。DefWindowProc用窗口过程接收到的相同参数调用。
语法:
LRESULT LRESULT DefWindowProcA( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
复制代码
参数说明:
——————————————————————————————————
所述的TextOut函数在指定位置写入的字符串,利用当前选择的字体,背景颜色和文本颜色。
语法:
BOOL TextOutW( HDC hdc, int x, int y, LPCWSTR lpString, int c );
复制代码
参数说明:
——————————————————————————————————
引用文档解释:
HDC代码中是设备上下文的句柄,这是 Windows 用于使应用程序与图形子系统通讯的数据结构。
销毁窗口时发送。从窗口中删除窗口后,它将被发送到销毁窗口的窗口过程。 此消息首先发送到被销毁的窗口,而后发送到被销毁的子窗口(若是有)。在处理消息期间,能够假定全部子窗口仍然存在。
WM_DESTROY 在 WndProc 函数中使用
——————————————————————————————————
当应用程序经过调用CreateWindowEx或CreateWindow函数请求建立窗口时发送。(在函数返回以前发送消息。)在建立窗口以后,但在该窗口变为可见以前,新窗口的窗口过程会收到此消息。
——————————————————————————————————
以后注册该窗口,使用 RegisterClassEx:
RegisterClassEx(&wcex);
复制代码
注册后使用 CreateWindow 进行注册的窗口建立语法以下:
HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, PVOID lpParam );
复制代码
参数说明:
建立窗体:
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 1000, NULL, NULL, hInstance, NULL);
复制代码
应用窗体名为 szWindowClass:
static TCHAR szWindowClass[] = _T("win32 Demo");
复制代码
应用窗体名为 szTitle:
static TCHAR szTitle[] = _T("This Win32");
复制代码
窗体风格类型为:WS_OVERLAPPEDWINDOW 初始位置为:CW_USEDEFAULT,默认左上角出现 尺寸为:1000, 1000 父级及菜单栏都为:NULL hInstance为:当前实例 hInstance lpParam应用程序使用为:NULL
代码以下:
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面应用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主页:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
复制代码
——————————————————————————————————
完成以上代码后,还需使用 ShowWindow 让Windows窗体指定如何显示,代码以下:
ShowWindow(hWnd, nCmdShow);
复制代码
语法:
BOOL ShowWindow( HWND hWnd, int nCmdShow );
复制代码
参数说明:
nCmdShow 参考:
使用 UpdateWindow 发送 WM_PAINT 消息,更新指定窗口。 语法:
BOOL UpdateWindow( HWND hWnd );
复制代码
参数:
总体代码以下:
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面应用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主页:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
复制代码
运行程序,发现出现了一闪而过的窗口,这个很像刚学习C语言的时候,没有加上中止;那咱们就循环侦听 Windows 发送的消息便可:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
复制代码
——————————————————————————————————
GetMessage
从调用线程的消息队列中检索消息。该函数分派传入的已发送消息,直到已发布的消息可供检索为止。
语法:
BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );
复制代码
参数说明:
——————————————————————————————————
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面应用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主页:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
复制代码
运行结果以下: