C语言学习day25:WinAPI编程进阶02-第一个窗口应用程序开发
简言
一个窗口的创建大致可以分为这几个步骤:1.初始化窗口结构体,2.注册窗口类,3.创建窗口,4.显示和更新窗口,5.消息循环
初始化窗口结构体
使用:WNDCLASS函数
语法:
typedef struct tagWNDCLASSA {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASSA, *PWNDCLASSA, *NPWNDCLASSA, *LPWNDCLASSA;
参数一:
style,
类型:UINT,类样式(s)。 此成员可以是 类样式的任意组合。Windows 类样式 (Winuser.h) - Win32 apps | Microsoft Learn
代码:
WNDCLASS wnd;
wnd.style=CS_HREDRAW|CS_VREDRAW;
参数二:
类型:WNDPROC
指向窗口过程的指针。 必须使用 CallWindowProc 函数来调用窗口过程。 有关详细信息,请参阅 WindowProc。
直接将函数原型拿来用:
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
return 1;
}
代码:
wnd.lpfnWndProc=WindowProc;
参数三:
要按照窗口类结构分配的额外字节数。系统将字节初始化为零。
(默认先不管)
参数四:
在窗口实例之后分配的额外字节数。 系统将字节初始化为零。如果应用程序使用 WNDCLASS 江册通过使用资源文件中 的 CLASS 指令创建的对话框,则必须将此成员设置为DLGWINDOWEXTRA.
(默认先不管)
参数五:
包含类的窗口过程的实例的句柄。
代码:
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
WNDCLASS wnd;
//直接填写服务的函数中的HINSTANCE
wnd.hInstance=hInstance;
return 0;
参数六:
类图标的句柄。此成员必须是图标资源的句柄。如果此成员为 NULL,则系统提供默认图标.
(目前正在学习,不用管图标)
参数七:
类游标的句柄。 此成员必须是游标资源的句柄。 如果此成员为 NULL,则每当鼠标移动到应用程序的窗口中时,应用程序都必须显式设置光标形状。(当光标移动到窗口时,显示不同的光标样式),当前阶段可设为NULL
参数八:
类背景画笔的句柄。 此成员可以是用于绘制背景的物理画笔的句柄,也可以是颜色值。 颜色值必须是以下标准系统颜色之一,(值1必须添加到所选颜色)。简单来说就是背景颜色,目前不用管,只用默认的COLOR_WINDOW
参数九:
类菜单的资源名称,因为名称显示在资源文件中。如果使用整数标识菜单,请使用MAKEINTRESOURCE 宏。如果此成员为 NULL,则属于此类的窗口没有默认菜单。(一定要有)
代码:
wnd.lpszClassName="Wechat:190";
总结代码:
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
return 1;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
//1.初始化窗口类结构
WNDCLASS wnd={0};
wnd.style=CS_HREDRAW|CS_VREDRAW;
wnd.lpfnWndProc=WindowProc;
wnd.hInstance=hInstance;
wnd.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wnd.lpszClassName="Wechat:190";
}
注册窗口类
使用registerClass()函数。
语法:
ATOM RegisterClassA(
[in] const WNDCLASSA *lpWndClass
);
参数:
类型:const WNDCLASS*
指向 WNDCLASS 结构的指针。 在将结构传递给函数之前,必须用相应的类属性填充结构。
代码:
RegisterClass(&wnd);
创建窗口
使用CreateWindowA()函数。
语法:
HWND CreateWindowA(
[in, optional] LPCSTR lpClassName,
[in, optional] LPCSTR lpWindowName,
[in] DWORD dwStyle,
[in] int x,
[in] int y,
[in] int nWidth,
[in] int nHeight,
[in, optional] HWND hWndParent,
[in, optional] HMENU hMenu,
[in, optional] HINSTANCE hInstance,
[in, optional] LPVOID lpParam
);
参数一:
类名,才初始化时已经创建,直接复制过来用。
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
参数二:
窗口名称,可自由设计:
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
参数三:
正在创建的窗口的样式。 此参数可以是 窗口样式值的组合,以及“备注”部分中指示的控件样式。
(准确数值可点击蓝色超链接,来进行查看)
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
参数四、五:
类型:int
窗口的初始水平位置/窗口的初始垂直位置:
从屏幕的最左上方,往右/下=都为正方向。
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100,
参数六、七:
类型:int
窗口的宽度/窗口的高度(以设备单位为单位)
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
参数八:
类型:HWND
正在创建的窗口的父窗口或所有者窗口的句柄。(我们现在默认就行:NULL)
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
NULL,
参数九:
类型:HMENU
菜单的句柄,或根据窗口样式指定子窗口标识符。(我们现在默认:NULL)
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
NULL,
NULL,
参数十:
类型:HINSTANCE
要与窗口关联的模块实例的句柄。
将我们的实例句柄填入:
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
NULL,
NULL,
hInstance,
);
}
参数十一:
类型:LPVOID
指向通过 CREATESTRUCT 结构(lpCreateParams 成员)指向的值的指针,该值由 WM_CREATE 消息的 lParam 参数指向。 此消息在返回之前由此函数发送到创建的窗口。
(目前我们不管,填写NULL,或是0)
代码:
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_EX_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
NULL,
NULL,
hInstance,0
);
返回值:
类型:HWND
如果函数成功,则返回值是新窗口的句柄。
如果函数失败,则返回值 NULL。 若要获取扩展的错误信息,请调用 GetLastError。
显示和更新窗口
使用ShowWindow()函数和UpdateWindow()函数
语法1:
showWindow():
BOOL ShowWindow(
[in] HWND hWnd,
[in] int nCmdShow
);
参数:
类型:HWND
窗口的句柄。
返回值:
类型: BOOL
如果窗口以前可见,则返回值为非零值。
如果以前隐藏窗口,则返回值为零。
语法2:
updateWindow():
BOOL UpdateWindow(
[in] HWND hWnd
);
参数:
类型:HWND
要更新的窗口的句柄。
返回值:
类型:BOOL
如果该函数成功,则返回值为非零值。
如果函数失败,则返回值为零。
消息循环
意识:windows操作系统---消息机制 消息投递、反应(行动)
以文本编辑软件为例子:
1.鼠标消息(可能还有按钮消息)---> windows操作系统
2.windows操作系统说可以 -->文本编辑软件就大了(因为对操作系统有很大的依赖性。
在消息循环中用到俩个API函数:GetMessage()和DispatchMessage()函数
代码:
MSG msg = {};
while (GetMessageA(&msg, 0, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
总结:
全代码
#include "framework.h"
#include "WindowsProject2.h"
#include <windows.h>
#define MAX_LOADSTRING 100
// 回调函数
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
MessageBoxA(NULL, "鼠标左键按下", "温馨提示", MB_OK);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProcA(hwnd,uMsg,wParam,lParam);
break;
}
return 0;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// 1.初始化窗口类结构
WNDCLASSA wnd = {0};
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = WindowProc;
wnd.hInstance = hInstance;
wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wnd.lpszClassName = "Wechat:190";
// 注册
RegisterClassA(&wnd);
// 创建窗口
HWND hWnd = CreateWindowA(
wnd.lpszClassName,
"第一个程序",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500,
NULL,
NULL,
hInstance,
0);
// 显示和更新窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
// 消息循环
MSG msg = {};
while (GetMessageA(&msg, 0, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
}
输出: