helloworld
#include<windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
MessageBox(NULL, TEXT("这里是内容"), TEXT("这里是标题"), MB_OK);
return 0;
}
MessageBox 参数分别是:句柄、窗体内容、窗体标题、摁钮选项
int MessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
MB_ABORTRETRYIGNORE about/retry/ignore
MB_CANCELTRYCONTINUE cancel/retry/continue
MB_HELP help
MB_OK ok
MB_OKCANCEL ok/cancel
MB_RETRYCANCEL retry/cancel
MB_YESNO yes/no
MB_YESNOCANCEL yes/no/cancel
在 uType 那里可以加上一些图标
MB_ICONEXCLAMATION 叹号警告
MB_ICONWARNING 叹号警告
MB_ICONINFORMATION 小 i 标志
MB_ICONASTERISK 小 i 标志
MB_ICONQUESTION 问号标志
MB_ICONSTOP 红叉标志
MB_ICONERROR 红叉标志
MB_ICONHAND 红叉标志
可以通过这里设置默认按键(摁下回车选择的那个键)
MB_DEFBUTTON1 指定第一个为默认按钮
MB_DEFBUTTON2
MB_DEFBUTTON3
MB_DEFBUTTON4
创建窗口
/* -------------------------------------------------------------------
MyWindows.c -- 基本窗口模型
《Windows 程序设计(SDK)》视频教程
这段代码,先敲五遍再说
--------------------------------------------------------------------*/
#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("MyWindows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("这个程序需要在 Windows NT 才能执行!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName,
TEXT("鱼C工作室"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
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_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, TEXT("大家好,这是我的第一个窗口程序!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
WNDCLASS 结构
typedef struct tagWNDCLASSW {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
成员解析:
成员 | 含义 |
---|---|
style | 指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来 |
lpfnWndProc | 指定窗口过程(必须是回调函数) |
cbClsExtra | 预留的额外空间,一般为 0 |
cbWndExtra | 预留的额外空间,一般为 0 |
hInstance | 应用程序的实例句柄 |
hIcon | 为所有基于该窗口类的窗口设定一个图标 |
hCursor | 为所有基于该窗口类的窗口设定一个鼠标指针 |
hbrBackground | 指定窗口背景色 |
lpszMenuName | 指定窗口菜单 |
lpszClassName | 指定窗口类名 |
style 类风格解析
类风格 | 含义 |
---|---|
CS_VREDRAW | 移动或者调整窗口的高度(垂直方向)时,重绘整个窗口 |
CS_HREDRAW | 移动或者调整窗口的宽度(水平方向)时,重绘整个窗口 |
CS_DBLCLKS | 当用户光标在窗口内双击时,允许发送双击消息给窗口过程 |
CS_OWNDC | 给予每个窗口实例分配一个唯一的 DC(注意,尽管这样是很方便,但它必须慎重使用,因为每个 DC 大约要占 800 个字节的内存) |
CS_CLASSDC | 该窗口类的所有窗口实例都共享一个窗口类 DC |
CS_PARENTDC | 1. 将子窗口的裁剪区域设置到父窗口的 DC 中去,这样子窗口便可以在父窗口上绘制自身。(注意,这是子窗口从系统缓存中获取 DC,而不是使用父窗口的 DC。) 2. 指定该风格可以提高系统性能 |
CS_NOCLOSE | 禁止系统菜单的关闭选项 |
CS_SAVEBITS | 1. 以位图形式保存被该窗口遮挡的屏幕部分,当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息 2. 该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失 3. 设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存 |
CS_BYTEALIGNCLIENT | 在字节边界上(在 x 方向上)定位窗口的用户区域的位置 |
CS_BYTEALIGNWINDOW | 在字节边界上(在 x 方向上)定位窗口的位置 |
CS_GLOBALCLASS | 1. 当调用 CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的 hInstance 参数和注册窗口类时传递给 RegisterClass 的 hInstance 参数不同 2. 如果不指定该风格,则这两个 hInstance 必须相同 |
转载自:https://fishc.com.cn/thread-47123-1-1.html
CreateWindow
HWND WINAPI CreateWindow(
_In_opt_ LPCTSTR lpClassName, // 窗口类名称
_In_opt_ LPCTSTR lpWindowName, // 窗口标题
_In_ DWORD dwStyle, // 窗口风格,或称窗口格式
_In_ int x, // 初始 x 坐标
_In_ int y, // 初始 y 坐标
_In_ int nWidth, // 初始 x 方向尺寸
_In_ int nHeight, // 初始 y 方向尺寸
_In_opt_ HWND hWndParent, // 父窗口句柄
_In_opt_ HMENU hMenu, // 窗口菜单句柄
_In_opt_ HINSTANCE hInstance, // 程序实例句柄
_In_opt_ LPVOID lpParam // 创建参数
);
参数解析:
参数 | 含义 |
---|---|
lpClassName | 1. 窗口类名称,可以是一个指向 NULL 结束的字符串或一个整型数值 2. 如果是字符串,它指定了窗口的类名。这个类名可以是任何用函数 RegisterClass 注册的类名,或是任何预定义的控制类名 3. 如是一个整型量,它是由此前调用 theGlobalAddAtom 函数产生的全局量。这个小于 0xC000 的 16 位数必须是 lpClassName 参数字的低 16 位,该参数的高位必须是 0 |
lpWindowName | 1. 窗口标题,一个指向 NULL 结束的字符串指针 2. 如果窗口风格指定了标题条,由 lpWindowName 指向的窗口标题将显示在标题条上 3. 当使用 Createwindow 函数来创建控制例如按钮,选择框和静态控制时,可使用 lpWindowName 来指定控制文本 |
dwStyle | 指定创建窗口的风格(详见下方↓) |
x | 1. 指定窗口的初始水平位置(x 坐标) 2. 对一个层叠或弹出式窗口,x 参数是屏幕坐标系的窗口的左上角的初始 x 坐标 3. 对于子窗口,x 是子窗口左上角相对父窗口客户区左上角的初始 x 坐标 4. 如果该参数被设为 CW_USEDEFAULT 则系统为窗口选择缺省的左上角坐标并忽略 y 参数,CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则 x 和 y 参数被设为零。 |
y | 1. 指定窗口的初始垂直位置(y 坐标) 2. 对一个层叠或弹出式窗口,y 参数是屏幕坐标系的窗口的左上角的初始 y 坐标 3. 对于子窗口,y 是子窗口左上角相对父窗口客户区左上角的初始 y 坐标 4. 对于列表框,y 是列表框客户区左上角相对父窗口客户区左上角的初始 y 坐标 5. 如果层叠窗口是使用 WS_VISIBLE 风格位创建的并且 x 参数被设为 CW_USEDEFAULT,则系统将忽略 y 参数 |
nWidth | 1. 以设备单元指明窗口的宽度 2. 对于层叠窗口,nWidth 的值或是屏幕坐标的窗口宽度或是 CW_USEDEFAULT 3. 若 nWidth 是 CW_USEDEFAULT,则系统为窗口选择一个默认的高度和宽度(默认宽度为从初始 x 坐标开始到屏幕的右边界,缺省高度为从初始 y 坐标开始到目标区域的顶部。),CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口和子窗口设定 CW_USEDEFAULT 标志则 nWidth 和 nHeight 被设为零 |
nHeight | 1. 以设备单元指明窗口的高度 2. 对于层叠窗口,nHeight 是屏幕坐标的窗口宽度 3. 若 nWidth 被设为 CW_USEDEFAULT,则系统忽略 nHeight 参数,自动为 nWidth 和 nHeight 设置默认参数 |
hWndParent | 1. 指向被创建窗口的父窗口或所有者窗口的句柄 2. 若要创建一个子窗口或一个从属窗口,需提供一个有效的窗口句柄 3. 创建一个单纯的消息窗口,可以提供 HWND_MESSAGE 或提供一个己存在的消息窗口的句柄 |
hMenu | 1. 指向窗口菜单句柄,或依据窗口风格指明一个子窗口标识 2. 对于层叠或弹出式窗口,hMenu 指定窗口使用的菜单:如果使用了菜单类,则 hMenu 可以为 NULL 3. 对于子窗口,hMenu 指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的 |
hInstance | 与窗口相关联的模块实例的句柄 |
lpParam | 1. 指向一个值的指针,该值传递给窗口 WM_CREATE 消息。该值通过在 IParam 参数中的 CREATESTRUCT 结构传递 2. 如果应用程序调用 CreateWindow 创建一个 MDI 客户窗口,则 lpParam 必须指向一个 CLIENTCREATESTRUCT 结构 |
dwStyle 窗口风格解析
窗口风格 | 含义 |
---|---|
WS_BORDER | 创建一个带边框的窗口 |
WS_CAPTION | 创建一个有标题框的窗口(包含了 WS_BODER 风格) |
WS_CHILD | 创建一个子窗口,这个风格的窗口不能拥有菜单也不能与 WS_POPUP 风格合用 |
WS_CHILDWINDOW | 与 WS_CHILD 相同 |
WS_CLIPCHILDREN | 当在父窗口内绘图时,排除子窗口区域,在创建父窗口时使用这个风格 |
WS_CLIPSIBLINGS | 1. 排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到 WM_PAINT 消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口 2. 如果未指定该风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口 |
WS_DISABLED | 1. 创建一个初始状态为禁止的子窗口,一个禁止状态的窗口不能接受来自用户的输入信息 2. 在窗口创建之后,可以调用 EnableWindow 函数来启用该窗口 |
WS_DLGFRAME | 创建一个带对话框边框风格的窗口,这种风格的窗口不能带标题条 |
WS_GROUP | 1. 指定一组“控制窗口”的第一个“控制窗口” 2. 这个“控制窗口”组由第一个“控制窗口”和随后定义的“控制窗口”组成,自第二个“控制窗口”开始每个“控制窗口”具有 WS_GROUP 风格 3. 每个组的第一个“控制窗口”带有 WS_TABSTOP 风格,从而使用户可以在组间移动 4. 用户随后可以使用光标在组内的控制间改变键盘焦点 |
WS_HSCROLL | 创建一个有水平滚动条的窗口 |
WS_ICONIC | 创建一个初始状态为最小化状态的窗口,与 WS_MINIMIZE 风格相同 |
WS_MAXIMIZE | 创建一个初始状态为最大化状态的窗口 |
WS_MAXIMIZEBOX | 创建一个具有最大化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_MINIMIZE | 创建一个初始状态为最小化状态的窗口,与 WS_ICONIC 风格相同 |
WS_MINIMIZEBOX | 创建一个具有最小化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_OVERLAPPED | 产生一个层叠的窗口,一个层叠的窗口有一个标题条和一个边框,与 WS_TILED 风格相同 |
WS_OVERLAPPEDWINDOW | 相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_TILEDWINDOW 风格相同 |
WS_POPUP | 创建一个弹出式窗口,该风格不能与 WS_CHILD 风格同时使用。 |
WS_POPUPWINDOW | 相当于(WS_POPUP | WS_BORDER | WS_SYSMENU),但 WS_CAPTION 和 WS_POPUPWINDOW 必须同时设定才能使窗口某单可见 |
WS_SIZEBOX | 创建一个可调边框的窗口,与 WS_THICKFRAME 风格相同 |
WS_SYSMENU | 创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格 |
WS_TABSTOP | 1. 创建一个“控制窗口”,在用户按下 Tab 键时可以获得键盘焦点。 2. 按下 Tab 键后使键盘焦点转移到下一具有 WS_TABSTOP 风格的“控制窗口” |
WS_THICKFRAME | 创建一个具有可调边框的窗口,与 WS_SIZEBOX 风格相同 |
WS_TILED | 产生一个层叠的窗口,一个层叠的窗口有一个标题和一个边框,与 WS_OVERLAPPED 风格相同 |
WS_TILEDWINDOW | 相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_OVERLAPPEDWINDOW 风格相同 |
WS_VISIBLE | 创建一个初始状态为可见的窗口 |
WS_VSCROLL | 创建一个有垂直滚动条的窗口 |
转自:https://fishc.com.cn/thread-47139-1-1.html
消息机制
windows 是事件驱动、基于消息的操作系统
switch (message) 然后对各种消息进行处理
文本输出
设备环境句柄
一开始要获得设备环境句柄 hdc
hdc = GetDC(hwnd);
ReleaseDC(hwnd, hdc);
上面获取句柄的方式是通用的,下面这种在响应 WM_PAINT 的时候使用
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
DrawText
int DrawText(
_In_ HDC hDC, //设备环境句柄
_Inout_ LPCTSTR lpchText, //指向将被写入的字符串的指针
_In_ int nCount, //指向字符串中的字符数
_Inout_ LPRECT lpRect, //指向 RECT 结构的指针
_In_ UINT uFormat //指定格式化文本的方法
);
RECT 结构定义了一个矩形的左上角和右下角的坐标GetClientRect(hwnd, &rect);
获取窗口客户区的坐标 RECT 结构,用 DrawText 之前先用这个获取 RECT 结构
TextOut
BOOL TextOut(
_In_ HDC hdc, //设备环境句柄
_In_ int nXStart, //x坐标
_In_ int nYStart, //y坐标
_In_ LPCTSTR lpString, //指向将被绘制字符串的指针
_In_ int cchString //长度(多少个字符)
);
StringCchPrintf
函数用于把数据格式化写入到指定的缓冲区里
StringCchPrintf(szBuffer,128,TEXT("%d: %s"),i+1,TEXT("yichen"));
HRESULT StringCchPrintf(
_Out_ LPTSTR pszDest, //缓冲区
_In_ size_t cchDest, //大小
_In_ LPCTSTR pszFormat,//格式化字符串
_In_ ... //格式化字符串的参数...
);
StringCchLength
用来确定长度是否超过了规定的大小
StringCchLength(szBuffer,12,&i_size);
HRESULT StringCchLength(
_In_ LPCTSTR psz, //缓冲区,待检查字符串
_In_ size_t cchMax, //规定的大小
_Out_ size_t *pcch //返回字符个数
);
获取各种尺寸
文本尺寸
GetTextMetrics
将当前字体信息填充到指定的缓冲区
BOOL GetTextMetrics(
_In_ HDC hdc, //环境句柄
_Out_ LPTEXTMETRIC lptm //指向 TEXTMETRIC 结构的指针
);
TEXTMETRICS tm;
GetTextMetrics(hdc,&tm); //拿到之后就能用tm结构体中的值了
cxChar = tm.tmAveCharWidth; //字符的宽度
cyChar = tm.tmHeight + tm.tmExternalLeading; //字符的高度
TEXTMETRIC结构体
记录当前设备环境中有关字体的各种信息
窗口尺寸
GetSystemMetrics
GetSystemMetrics(SM_CXSCREEN); //屏幕宽度
GetSystemMetrics(SM_CYSCREEN); //屏幕高度
//显示屏幕分辨率,单位是像素
客户区尺寸
LOWORD(lParam) 表示 x 轴
HIWORD(lParam) 表示 y 轴
添加滚动条
在 CreateWindow 的第三个参数加上 WS_VSCROLL(纵向滚动条)WS_HSCROLL(横向滚动条)