下一篇
我最近在学MFC,但是在此之前学了一下直接用WINAPI来写win32窗体程序。
以下就是我直接用C语言调用WINAPI来写win32窗体程序了,详细的就不讲了,代码注释应该很清楚了。
之后我会将后面我学到的内容发布出来,希望能和其他小白新手一起进步。
需要注意的地方:
(1)
CreateWindowExW()//使用这个函数或者使用CreateWindow函数,
//如果使用了CreateWindowExA()函数窗体程序不会报错但是也不会显示出来
(2)
这个PostQuitMessage(0)是起退出程序的作用,没有这个,即使销毁了窗体(点击右上角的叉叉),程序也不会退出。
case WM_DESTROY:
PostQuitMessage(0);//发送程序退出消息
break;
(3)
这些常量的意思可以去MicrosoftDoc查阅
IDI_APPLICATION
IDC_ARROW
CW_USEDEFAULT
WM_CLOSE
#include
//CALLBACK 代表 _stdcall 参数的传递顺序:从右到左以此入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
//WINAPI 代表 _stdcall参数的传递顺序:从右到左以此入栈,并且在函数返回前清空堆栈
int WINAPI WinMain(
HINSTANCE hInstance,//应用程序实例化句柄
HINSTANCE hPrevInstance,//上一个应用程序句柄,一般为NULL。
LPSTR lpCmdLine,//命令行参数 类似于 char *argv[]
int nShowCmd//窗口显示命令,列如 最大化,最小化,正常
)
{
/*
步骤
1、设置窗口
2、注册窗口
3、创建窗口
4、显示和更新
5、循环取消息
6、处理消息(窗口过程)
*/
HWND hwnd;//窗口句柄
//1、设置窗口
//WNDCLASS wc;
//WNDCLASSEXA wcEXA;//窗口类
WNDCLASS wcEXA;//窗口类
//wcEX.hInstance
wcEXA.cbClsExtra = 0;
wcEXA.cbWndExtra = 0;
wcEXA.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcEXA.hCursor = LoadCursorA(NULL, IDC_ARROW);//设置光标//在LoadCursorA中,参数1为NULL表示使用系统默认光标,参数2 IDC_ARROW 表示标准箭头光标(其他可参考 MSDN )
wcEXA.hIcon = LoadIconA(NULL, IDI_APPLICATION);//窗口图标//参数1为NULL表示使用系统默认图标,参数2 IDI_APPLICATION 表示默认应用图标
wcEXA.hInstance = hInstance;//应用程序实例化句柄,传入WINMAIN 中的 hInstance 形参即可
wcEXA.lpfnWndProc = WindowProc;//回调函数//指向应用程序定义的函数的指针,该字段称为窗口过程或“窗口过程 ”
wcEXA.lpszClassName = TEXT("MyWindows");//指定窗口类名
//wcEXA.lpszMenuName = TEXT("MyMenu");//指定菜单名称//不使用菜单则为 NULL
wcEXA.lpszMenuName = NULL;//指定菜单名称//不使用菜单则为 NULL
wcEXA.style = CS_HREDRAW | CS_VREDRAW;;//指定窗口风格//为0为默认样式
//2、注册窗口(类)
if (!RegisterClass(&wcEXA)) {
MessageBox(NULL, TEXT("程序只能在windowsNT下运行"),
TEXT("MyWindows"), MB_ICONERROR);
return 0;
}
//3、创建窗口
/* CreateWindowExA函数的参数列表
DWORD dwExStyle, //窗口扩展风格 //WS_EX_OVERLAPPEDWINDOW
LPCSTR lpClassName, //类名
LPCSTR lpWindowName, //窗口标题名
DWORD dwStyle, //窗口风格 //WS_CAPTION常量表示该窗口具有标题栏//WS_OVERLAPPEDWINDOW
int X, //窗口坐标x
int Y, //窗口坐标y
int nWidth, //窗口宽度
int nHeight, //窗口高度
HWND hWndParent, //窗口的父窗口句柄
HMENU hMenu, //窗口菜单
HINSTANCE hInstance, //窗口实例句柄
LPVOID lpParam //附加值,一般为鼠标的附加值
*/
hwnd=CreateWindowExW(
WS_EX_OVERLAPPEDWINDOW,
wcEXA.lpszClassName,
TEXT("我的窗口"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
//4、显示和更新
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
//5、循环取消息
/* MSG(消息)类型的结构
HWND hwnd; //窗口句柄
UINT message; //消息标识符(消息名称)//应用程序只能使用低位字
WPARAM wParam; //附加消息。确切含义取决于消息成员的值 。(一般为键盘消息)
LPARAM lParam; //附加消息。确切含义取决于消息成员的值 。(一般为鼠标按键消息)
DWORD time; //消息发布(产生)的时间。
POINT pt; //消息发布时的光标位置,以屏幕坐标表示。(点的位置消息,如鼠标所在点)
*/
MSG msg;//消息
while (1)
{
/* GetMessageW函数参数列表
LPMSG lpMsg, //MSG类型的指针
HWND hWnd, //提供指定窗口的窗口句柄,以捕获指定窗口的消息//NULL表示捕获当前线程所有窗口的消息//-1表示当前线程当前消息队列
UINT wMsgFilterMin, //最小的过滤消息,一般为0,0表示捕获消息队列中的所有消息
UINT wMsgFilterMax); //最大的过滤消息,一般为0,0表示捕获消息队列中的所有消息
*/
if (GetMessage(&msg, NULL, 0, 0) == FALSE) {
break;
}
//翻译消息
TranslateMessage(&msg);
//GetMessageW函数返回值不为FALSE则分发消息
//分发消息
DispatchMessage(&msg);
}
return msg.wParam;
}
//6、处理消息(窗口过程)
//CALLBACK 代表 _stdcall 参数的传递顺序:从右到左以此入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
HWND hwnd, //消息所处的窗口句柄
UINT uMsg, //具体的消息名称 一般名字格式为 WM_xxxxxx
WPARAM wParam, //键盘附加消息
LPARAM lParam) //鼠标附加消息
{
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);//发送另一个消息 WM_DESTROY
break;
case WM_DESTROY:
PostQuitMessage(0);//发送程序退出消息
break;
case WM_PAINT: {
PAINTSTRUCT ps;//绘图结构体
HDC hdc=BeginPaint(hwnd,&ps);//开始绘图
TextOut(hdc, 10, 10, TEXT("hello"),strlen("hello"));
EndPaint(hwnd, &ps);//结束绘图
}
break;
default:
break;
}
return DefWindowProc(hwnd,uMsg,wParam, lParam);//返回值使用默认处理方式
}