//作为学习win32程序的笔记(持续更新中)
Win32 的 Windows 界面开发通常使用 C 语言来编写。Win32 API(Application Programming Interface)提供了一套用于操作 Windows 系统的函数,结构体和常量,开发者可以使用这些 API 来创建 Windows 应用程序的用户界面。
在 Win32 编程中,可以使用纯 C 语言编写代码来调用 Win32 API 函数,创建窗口、处理消息、设置控件等。通过注册窗口类、创建窗口、处理消息循环等操作,开发者可以自定义实现 Windows 应用程序的界面和功能。
虽然在 Win32 编程中使用 C 语言最为常见,但也可以结合 C++ 等其他语言来进行开发。此外,Microsoft Foundation Classes(MFC)是一个基于 C++ 的库,提供了对 Win32 API 的封装,使得 Windows 界面开发变得更加方便。
学习MFC之前,有必要了解win32的相关内容。本文整理了相关API,以作为学习参考。
(使用vs2022)
前言:
vs创建win32程序步骤如下:
1新建空项目,创建一个cpp文件,打开项目属性页面。
设置为窗口
选择性设置字符为多文本(本人没改)
2 新建资源。解决方案列表-项目名称右键
更改项目图标 找个icon图标放在项目目录中 ,下图Import即可
增加对话框
选择dialog,new
另:对控件包括对话框本身修改ID后,需要打开文件,对重复的控件ID定义删除(vs的bug)(也就是修改的ID和以前的ID同时存在,把旧的删除)
API记录:
1 winmain
入口,win32的入口函数不再是main函数(有界面的)而是winmain(在help viewer的词条是WinMain entry point)
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
) {
// 在这里编写应用程序初始化的代码
// 创建窗口、消息循环等
// 最后返回程序的退出码
return 0;
}
参数说明
hInstance
:当前应用程序实例句柄。hPrevInstance
:先前实例句柄,在现代 Windows 中始终为 NULL,因为 Windows 不再支持多实例应用程序。lpCmdLine
:指向包含命令行参数的 ANSI 字符串的指针,通常用于从命令行中传递参数。nCmdShow
:指示应用程序窗口应该如何显示的标志。
返回值
- 返回值类型为 int,通常表示应用程序的退出码。
说明
WinMain
是 Windows 主窗口应用程序的 ANSI 版本的入口点函数。- 在 Windows 中,Unicode 版本的入口点函数通常为
wWinMain
。 - 在
WinMain
函数中,可以进行应用程序初始化、创建窗口,实现消息循环以及处理窗口消息等。
另:
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
);
这个 WinMain
函数的定义与之前提到的 WinMain
函数定义基本相同,唯一的区别在于参数的修饰符以及函数声明中的 CALLBACK
宏。
在这个函数声明中:
_In_
:表示这是一个输入参数。CALLBACK
:是一个宏,一般定义为__stdcall
调用约定,用于标记函数作为回调函数。
这两个定义的 WinMain
函数实际上在参数和调用约定上没有本质区别,它们都是 Windows 主窗口应用程序的入口点函数,用来初始化应用程序、处理消息循环等操作。根据个人偏好或项目要求,可以选择其中的一种来作为程序的入口点函数。
【PS :程序中的_In_ 只是注释,说明是输入参数,类似还有 _In_opt_
指示参数是输入参数,并且可以为可选参数;_Out_
表示该参数是一个输出参数】
以下是wwinmain的定义:
int WINAPI wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PWSTR pCmdLine,
int nCmdShow
);
参数
hInstance
:当前应用程序实例的句柄。hPrevInstance
:先前实例的句柄,在现代 Windows 中始终为 NULL。pCmdLine
:指向包含命令行参数的 Unicode 字符串的指针。这是一个包含命令行参数的字符串,通常用于从命令行中传递参数。nCmdShow
:指示应用程序应如何被显示的标志,如最小化、最大化等。
返回值
- 返回值类型为 int,通常表示应用程序的退出码。
说明
wWinMain
是 Windows GUI 应用程序的入口点函数,主要用于创建窗口、消息循环和处理窗口消息。- 在 Windows 中,Unicode 版本的主窗口入口点函数命名为 wWinMain,对应的 ANSI 版本为 WinMain。
- 一般情况下,开发 Windows GUI 应用程序时会使用 wWinMain 函数作为程序的主入口点。
2 MessageBox 弹出消息:图标和文字
最后一个参数详见help viewer中的说明
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
参数说明:
hWnd
:父窗口的句柄,消息框将在其上显示,通常为NULL
。lpText
:消息框显示的文本内容。lpCaption
:消息框的标题。uType
:指定消息框的样式,包括按钮类型、图标类型、默认按钮和其他选项。
返回值:
- 返回值为用户的响应,可以是以下值之一:
IDOK
: 用户单击了“确定”按钮。IDCANCEL
:用户单击了“取消”按钮。- 其他值取决于消息框的样式和用户的选择。
举例用法:
int n = MessageBox(handle,L"Hello word",L"提示", MB_OKCANCEL | MB_ICONINFORMATION);
if (n == IDOK)
{
MessageBox(handle,L"你点击了OK",L"返回值",MB_OK);
}
3FindWindow 查找主窗口:根据标题或者窗口类型
HWND WINAPI FindWindow(
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName
);
第一个参数,可以使用spy++获取(vs的工具-Spy++)
使用 查找窗口 拖动
到窗口上,第一个参数使用句柄或者类都行(然后测试句柄失败了)
第二个参数标题,需要给出全称,比如:
HWND handle = FindWindow(NULL,L"API汇总1 - Notepad");//打开的某个窗口
4 SetWindowText 设置标题文字
BOOL WINAPI SetWindowText(
_In_ HWND hWnd,
_In_opt_ LPCTSTR lpString
);
5 GetWindoeText 获取窗口标题文字
int WINAPI GetWindowText(
_In_ HWND hWnd,
_Out_ LPTSTR lpString,
_In_ int nMaxCount
);
示例:
HWND handle = FindWindow(NULL,L"API汇总1 - Notepad");//打开的某个窗口
WCHAR s[100];
n = GetWindowText(handle, s, sizeof(s));
6 MoveWindow 改变窗口位置和大小
BOOL WINAPI MoveWindow(
_In_ HWND hWnd,
_In_ int X,
_In_ int Y,
_In_ int nWidth,
_In_ int nHeight,
_In_ BOOL bRepaint
);
例如,在对话框初始化时居中显示:
switch (uMsg)
{
case WM_INITDIALOG:
{
int screenW = GetSystemMetrics(SM_CXSCREEN);//屏幕宽
int screenH = GetSystemMetrics(SM_CYSCREEN);//长
LPRECT lpRect = new RECT;
GetWindowRect(hwndDlg, lpRect);
int w = lpRect->right;
int h = lpRect->bottom;
MoveWindow(hwndDlg, (screenW - w) / 2, (screenH - h) / 2, w, h, FALSE);
break;
}
}
7 EnableWindow 窗口禁用和激活
BOOL WINAPI EnableWindow(
_In_ HWND hWnd,
_In_ BOOL bEnable
);
8 ShowWindow 隐藏和显示窗口
不止用于隐藏和显示,还有最大化,最小化和恢复等功能。
BOOL WINAPI ShowWindow(
_In_ HWND hWnd,
_In_ int nCmdShow
);
示例:
switch (uMsg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_BTN_ENABLE: //自定义的一个按钮
{
HWND h = (HWND)lParam;
if (h)
EnableWindow(h, FALSE);
break;
}
case IDC_BTN_SHOW: //自定义的一个按钮
{
HWND h = GetDlgItem(hwndDlg, IDOK); //默认的ok按钮
if (h)
ShowWindow(h, SW_HIDE);
break;
}
}
break;
}
}
9 GetWindowRect 获取窗口位置和大小
BOOL WINAPI GetWindowRect(
_In_ HWND hWnd,
_Out_ LPRECT lpRect
);
例如:
LPRECT lpRect = new RECT;
GetWindowRect(hwndDlg, lpRect);
int w = lpRect->right;
int h = lpRect->bottom;
10 DialogBox对话框窗口 弹出消息:图标和文字
INT_PTR WINAPI DialogBox(
_In_opt_ HINSTANCE hInstance,//必须从WinMain的第一个参数获取
_In_ LPCTSTR lpTemplate,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc
);
最后参数是回调函数,函数类型如下:
typedef INT_PTR (CALLBACK* DLGPROC)(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
参数说明:
-
hwndDlg:表示当前处理消息的对话框窗口句柄。您可以使用此句柄来操作对话框,例如在对话框中查找控件,设置控件属性等。
-
message:表示接收到的消息类型。根据消息类型进行适当的处理,如在
switch
语句中针对不同的消息进行不同的操作。 -
wParam:表示与消息相关的附加信息,通常用于传递一些简单的参数或数据。具体含义取决于收到的消息类型。
-
lParam:也是用于传递消息相关的附加信息,但相对于
wParam
可以传递更多复杂的数据,例如指针、句柄等。同样,具体含义取决于收到的消息类型。
示例:
INT_PTR CALLBACK theProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (wParam) //lParam 是控件的句柄
{
case IDOK:
MessageBox(hwndDlg,L"你点击了ok",L"提示",0);
break;
case IDCANCEL:
if (IDYES == MessageBox(hwndDlg, L"你确认退出吗", L"提示", MB_YESNO | MB_ICONQUESTION))
{
EndDialog(hwndDlg,888);
}
break;
}
break;
}
return 0;
}
(WM_COMMAND 中 wParam是控件ID,Lparam是控件句柄)
11 EndDialog 关闭对话框
BOOL WINAPI EndDialog(
_In_ HWND hDlg,
_In_ INT_PTR nResult
);
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
}
return TRUE;
}
return FALSE;
}
12 GetDlgItem 获取控件句柄
HWND WINAPI GetDlgItem(
_In_opt_ HWND hDlg,
_In_ int nIDDlgItem
);
13 GetDlgItemText 获取控件文字
UINT WINAPI GetDlgItemText(
_In_ HWND hDlg,
_In_ int nIDDlgItem,
_Out_ LPTSTR lpString,
_In_ int nMaxCount
);
另:第三个参数如果使用动态数组,预防数组溢出,如:
int textLengthLeft = GetWindowTextLength(hLeft);
TCHAR* sLeft = new TCHAR[textLengthLeft + 1];
GetWindowText(hLeft, sLeft, textLengthLeft + 1);
其中GetWindowTextLength获取指定窗口(通常是编辑框控件或者组合框控件)中的文本长度
int WINAPI GetWindowTextLength(
_In_ HWND hWnd
);
14 SetDlgItemText 设置控件文字
BOOL WINAPI SetDlgItemText(
_In_ HWND hDlg,
_In_ int nIDDlgItem,
_In_ LPCTSTR lpString
);
另:第三个参数如果要动态分配,例 把double类型的数值写入控件:
// 计算格式化后字符串的长度
int size = _scwprintf(L"%g", fValue) + 1;
wchar_t* s = new wchar_t[size];
// 将double型数据格式化存入字符串s
swprintf(s, size, L"%g", fValue); //_snwprintf_s
// 设置控件的文本
BOOL result = SetDlgItemText(hDlg, nIDDlgItem, s);
delete[] s; // 释放动态分配的内存
其中_scwprintf 用于计算格式化后字符串长度的函数
int _scwprintf(
const wchar_t *format [,
argument] ...
);
类似的还有:
_scprintf, _scprintf_l, _scwprintf, _scwprintf_l …… |
15 WINDOWS位运算
定义在库minwinde.h中
#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
#define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
1 MAKELONG 把两个2字节数合成一个四字节
DWORD MAKELONG(
WORD wLow,
WORD wHigh
);
2 MAKEWORD 合成两字节
WORD MAKEWORD(
BYTE bLow,
BYTE bHigh
);
3 LOWORD 取出四字节中的两个低字节
WORD LOWORD(
DWORD dwValue
);
4 HIWORD 取出四字节中的两个高字节
WORD HIWORD(
DWORD dwValue
);
5 LOBYTE 取出两字节数中的低字节
BYTE LOBYTE(
WORD wValue
);
6 HIBYTE 取出两字节数中的高字节
BYTE HIBYTE(
WORD wValue
);
示例:
DWORD dw = MAKELONG(0x5678,0x1234); //0X12345678
WORD w = MAKEWORD(0X34, 0X12); //0X1234
WORD x = LOWORD(dw); //0X5678
WORD y = HIWORD(dw); //0X1234
BYTE a = LOBYTE(x); //0X78
BYTE b = HIBYTE(x); //0X56
16 OutputDebugString向调试器输出调试信息
void WINAPI OutputDebugString(
_In_opt_ LPCTSTR lpOutputString
);
17 GetSystemMetrics 获取系统级变量的值
例如屏幕大小、图标大小、滚动条大小等
int WINAPI GetSystemMetrics(
_In_ int nIndex
);
参数说明:
nIndex
:要查询的系统指标的索引。
返回值:
- 返回系统指标的值。具体的含义取决于传入的
nIndex
参数。
int screenWidth = GetSystemMetrics(SM_CXSCREEN);//屏幕宽
int screenHeight = GetSystemMetrics(SM_CYSCREEN);//屏幕高
int scrollWidth = GetSystemMetrics(SM_CXVSCROLL);//滚动条宽
int scrollHeight = GetSystemMetrics(SM_CYVSCROLL);//滚动条高
18 IsWindow 判断窗口是否存在或者已摧毁
BOOL IsWindow(
HWND hWnd
);
19 IsWindowEnabled 判断窗口是否激活或者禁用
BOOL WINAPI IsWindowEnabled(
_In_ HWND hWnd
);
示例:
HWND h = GetDlgItem(hwndDlg, IDOK);
EnableWindow(h, !IsWindowEnabled(h));
20 IsWindowVisible 判断窗口是否显示或隐藏
BOOL WINAPI IsWindowVisible(
_In_ HWND hWnd
);
21 SetTimer 设置定时器
UINT_PTR SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);
参数说明:
hWnd
:指定接收定时器消息的窗口句柄。nIDEvent
:指定定时器的 ID 值,用于标识特定的定时器,可以通过它来取消定时器。uElapse
:指定定时器的时间间隔,以毫秒为单位。lpTimerFunc
:可选参数,指向定时器过程的指针。如果为NULL,则发送WM_TIMER消息
返回值:
- 返回值为定时器的唯一标识符,用于标识该定时器。如果函数调用失败,则会返回0。
示例:
switch (uMsg)
{
case WM_TIMER:
{
//定时器进入
LPRECT lpRect = new RECT;
GetWindowRect(hwndDlg, lpRect);
int w = lpRect->right - lpRect->left;
int h = lpRect->bottom - lpRect->top;
MoveWindow(hwndDlg, lpRect->left + 2, lpRect->top, w, h, FALSE);//窗口向右移动
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BTN_TIMER: //按下自定义按钮,开启定时器
SetTimer(hwndDlg,1,1000,NULL);
break;
}
return TRUE;
}
附:
1.简单的windows数据类型
数据类型 | 源数据类型 | 含义 |
BOOL | int | 布尔型,主要财值对象是 TRUE和FALSE |
BYTE | unsiged char | 单字节(8bits)无符号变量 |
WORD | unsigred short | 双字节(16bits)无符号变量 |
DWORD | unsigred long | 4字节(32bits)无符号变量 |
UINT | unsigned int | 4字节(32bits)无符号变量 |
CHAR | char | 单字节(8bits)有符号变量 |
SHORT | short | 双字节(16bits)有符号变量 |
LONG | 1ong | 4字节(32bits)有符号变量 |
INT | int | 4字节(32bits)有符号变量 |
VOID | void | 无类型 |
PBOOL或 LPBOOL | BOOL* | BOOL 的指针类型 |
PBYTE 或 LPBYTE | BYTE* | BYTE 的指针类型 |
PWORD 或 LPWORD | WORD* | WORD 的指针类型 |
PDWORD 或 LPDWORD | DWORD* | DWORD 的指针类型 |
PCHAR | CHAR* | CHAR 的指针类型 |
PSHORT | SHORT* | SHORT 的指针类型 |
PLONG或LPLONG | LONG* | LONG 的指针类型 |
PINT 或LPINT | INT* | INT韝益 的指针类型 |
PVOID 或LPVOID | VOID* | 无类型指针,可以指向任何类型的数据. |
PSTR 或LPSTR | char* | 常用于指向字符串的指针 |
PCSTR 或 LPCSTR | const char* | 常用于指向字符串常量的指针 |
LRESULT | 32位:LONG 64位:LONG _PTR | 常用于函数返回值类型 |
WPARAN | 32位:UNIT 64位:UINT _PTR | 用于消息发送时的携带数据 |
LPARAM | 32位:LONG 64位:LONG PTR | 用于消息发送时的携带数据 |
2 句柄类型
数据类型 | 源数据类型 | 舍义 |
HANDLE | void* | 通用句柄类型 |
HWND | struct HWND_* | 窗口句柄 |
HDC | struct HDC_* | 设备内容句柄(或叫绘图句柄) |
HPEN | struct HPEN_* | 西笔句柄(或叫边框句柄) |
HBRUSH | struct HBRUSH_* | 西刷句柄(或叫填充句柄) |
HFONT | struct HFONT_* | 宁体句柄 |
HBITMAP | struct HBITMAP_* | 位图句柄 |
HGDIOBJ | void* | 通用 CDI对象句柄 |
HMENU | struct HMENU_* | 菜单句柄 |
HICON | struct HICON_* | 图标句柄 |
HCURSOR | struct HCURSOR_* | 光标句柄 |
HINSTANCE | struct HINSTANCE * | 模块实例句柄 |
HMODULE | HINSTANCE | 模块实例句柄 |
3 常用结构体类型
POINT (PPOINT) (LPPOINT) | typedef struct tagPOINT { LONG cx; LONG cy; }POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT; | X,y 坐标点 |
SIZE (PSIZE) (LPSIZE) | typedefstruct tagSIZE { LONG cx; LONG cy; }SIZE,*PSIZE,*LPSIZE; | 高宽尺寸 |
RECT (PRECT) (LPRECR) | typedefstruct tagREC T { LONG left; LONG top; LONG right; LONG bottom; }RECT,*PRECT,NEAR *NPRECT,FAR *LPRECT; | 上下左石 矩形区域 |
4一个基本的win32 对话框程序
#include <windows.h>
#include "resource.h"
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL: // eg: 按下cancel按钮
EndDialog(hwndDlg, IDCANCEL);
break;
}
return TRUE;
}
// 对于未处理的消息,调用DefWindowProc函数
return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
INT_PTR h = DialogBox(hInstance, (LPCTSTR)IDD_DIALOG1, NULL, DialogProc);
return 0;
}