概述
现代的桌面应用基本上很少使用原始的 Windows API 进行开发了,因为使用原始 API 堆砌出来的应用代码逻辑非常繁琐,特别是窗口消息的处理非常不方便,大多数直接使用 C# 或者 QT 这种跨平台的开发库,而那种直接封装 Windows API 而存在的 MFC 早已半步入土。
文章目录
- windows程序内部运行机制
- 窗口与句柄
- 消息与队列
- 想知道WM_XXX消息对应的具体数值?
- 消息队列
- WinMain函数
- WinMain 函数的原型声明如下:
- 窗口的创建
- 设计一个窗口类
- CS_开头的类样式(class style)
- lpfnWndProc---一个函数指针-----指向 窗口过程函数(是一个回调函数)
- 第三个成员变量--cbClsExtra
- 第四个----cbWndExtra
- 第五个hInstance ---窗口过程的实际句柄
- 第六个 hIcon 图标句柄
- 第七个--hCursor是一个光标资源
- 第八个hbrBackground---窗口类的背景画刷句柄
- 第九个lpszMenuName----以空终止的字符串---指定菜单资源的名字
- 第十个lpszClassName----以空终止的字符串---指定窗口类的名字
- 注册窗口类
- 创建窗口
- /符号的意义
- 显示及更新窗口
- 更新窗口
- 消息循环
- `TranslateMessage`---将虚拟键消息转化为字符消息
- `DispatchMessage`----分派一个消息到窗口过程
- PeekMessage
- windows应用程序的消息处理机制
- 编写窗口过程函数
- 匈牙利命名法
- 变量属性
- 属性部分:
- 类型部分:
- MFC、句柄、控件及结构的命名规范:
- Windows类型 样本变量;MFC类 样本变量
- 一般前缀命名规范:
- 前缀&类型&实例
- 变量命名规范:
- 前缀_符号类型:
- Microsoft MFC宏命名规范:
- 库标识符命名法:
- 静态库版本命名规范:
- 动态连接库命名规范:
windows程序内部运行机制
- 学习程序运行机制,为学习MFC打下基础。
- 我们常用库函数printf----这些C库函数都是编译器厂商提供的。在windows平台下面也有类似的库函数,但这是windows操作系统提供的。
- 所有主要的windows函数都在Windows.h头文件进行了声明。
- 这些api不可能都记住。我们要用的时候可以在MSDN里面查找。
- 从室内高人转为室外高人;
- 比如开发呼叫中心,我们会有厂商提供的语音卡SDK;
窗口与句柄
- 我们启动Windows系统后,看到的桌面也是个窗口,成为桌面窗口,由OS创建和维护。
- 窗口通过句柄识别:HWND
- 创建各种资源的时候也会返回他们的句柄:图标句柄HICON,光标句柄HCURSOR
消息与队列
- 系统反过来调用用户进程---------这个调用通过–消息—实现
- 事件驱动设计程序
- 操作系统感知到事件,投递到应用程序的消息队列
- 发送消息----------操作系统调用程序专门处理消息的函数--------窗口过程
typedef struct tagMSG {
HWND hwnd; //该消息所属的窗口句柄
UINT message; //指定消息的类型
WPARAM wParam; //用于指定消息的附加信息,根据消息不同,代表不同意思
LPARAM lParam; //用于指定消息的附加信息,根据消息不同,代表不同意思
DWORD time; //该消息投递到消息列队当中的时间
POINT pt; //该消息投递到消息列队当时,鼠标的当前位置
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
第一个参数:hwnd hwnd是一个窗口句柄,用于区别该消息属于哪一个窗口,可以说是一个窗口的编号。一个消息一般都与某个窗口相关联,比如鼠标移动到某个窗口中按下鼠标左键,该窗口就会收到一个“WM_LBUTTONDOWND”的消息,而应用程序就是利用消息中的hwnd值来 确定该消息到底是属于众多窗口中的哪一个窗口的。
第二个参数:message 为消息类型,该值为一个数值,不同的数值表示不同的消息,为了便于记忆,windows 为不同的消息定义了不同的宏,WM_XXX。(WM是windows message的缩写),例如 WM_LBUTTONDOWN 消息 按下鼠标左键的消息是 WM_KEYDOWN 消息 表示按下键盘上的某个键等等。
第三个参数:wParam WPARAM类型 根据不同的消息 代表不同的意思:例如 当收到 WM_LBUTTONDOWN 消息时,wParam 鼠标按钮、Shift和Ctrl键的状态。
第四个参数:lParam LPARAM类型 WPARAM类型 根据不同的消息 代表不同的意思:例如 当收到 WM_SIZE 消息时候 lParam - 客户区的大小。 LOWORD(底位) - 客户区的宽度。 HIWORD(高位) - 客户区的高度。
第五个参数:time -表示收到该消息的时间
第六个参数:pt -表示收到该消息时鼠标的当前位置
想知道WM_XXX消息对应的具体数值?
选中后,右键点击转到定义
消息队列
- OS将消息放到程序的队列,等待处理
- 进队消息&不进队消息
- 不进队消息:调用窗口过程时候,直接发送给窗口
WinMain函数
- windows程序入口函数
- 与dos程序入口main作用相同
WinMain 函数的原型声明如下:
int WINAPI WinMain(
HINSTANCE hInstance , // handle to current instance
HINSTANCE hPrevInstance , // handle to previous instance
LPSTR lpCmdLine , // command line
int nCmdShow // show state
);
WinMain 函数接收 4 个参数,这些参数都是在系统调用 WinMain 函数时,传递给应用程序的。
第一个参数 hInstance 表示该程序当前运行的实例的句柄,这是一个数值。当程序在 Windows 下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例,才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过 hInstance 参数传递给 WinMain 函数。
第二个参数 hPrevInstance 表示当前实例的前一个实例的句柄。通过查看 MSDN 我们可以知道,在 Win32 环境下,这个参数总是 NULL ,即在 Win32 环境下,这个参数不再起作用。
第三个参数 lpCmdLine 是一个以空终止的字符串,指定传递给应用程序的命令行参数。 例如:在 D 盘下有一个 sunxin.txt 文件,当我们用鼠标双击这个文件时将启动记事本程序( notepad.exe ),此时系统会将 D:/sunxin.txt 作为命令行参数传递给记事本程序的 WinMain 函数,记事本程序在得到这个文件的全路径名后,就在窗口中显示该文件的内容。要在 VC++ 开发环境中向应用程序传递参数,可以单击菜单 【 Project 】→【 Settings 】,选择“ Debug ” 选项卡,在“ Program arguments ”编辑框中输入你想传递给应用程序的参数。
第四个参数 nCmdShow 指定程序的窗口应该如何显示,例如最大化、最小化、隐藏等。这个参数的值由该程序的调用者所指定,在调用ShowWindow()时可以使用到该值。
窗口的创建
设计一个窗口类
- windows给我们设计好了,只需要做填空,就能创建很好的类
- 结构WNDCLASS包含一个窗口类的全部信息,也是Windows编程中使用的基本数据结构之一,应用程序通过定义一个窗口类确定窗口的属性,定义如下:
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
style: 指定类风格。这些风格可通过按位或操作组合起来。风格如下:
CS_BYTEALIGNCLIENT: 在字节边界上(在x方向上)定位窗口的用户区域的位置
CS_BYTEALIGNWINDOW: 在字节边界上(在x方向上)定位窗口的位置
CS_CLASSDC: 该窗口类的所有窗口实例都共享一个窗口类DC
CS_DBLCLKS: 允许向窗口发送双击鼠标键的消息
CS_GLOBALCLASS: 当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给
RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个 hInstance 必须相同。
CS_HREDRAW: 当水平长度改变或移动窗口时,重画整个窗口
CS_NOCLOSE: 禁止系统菜单的关闭选项
CS_OWNDC: 给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。
CS_PARENTDC: 将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。
CS_SAVEBITS: 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。
CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口
CS_开头的类样式(class style)
- 在WinUser.h里面,被定义为16位的常量
- 转为2进制发现-----16位上只有一个1
- 如果重绘窗口----------去掉某个样式可以&(某个样式取反)
- 由此可以用或( | )运算-------把两个样式组合起来
lpfnWndProc—一个函数指针-----指向 窗口过程函数(是一个回调函数)
-
特定事件发生产生有另一方调用,用于相应事件
-
窗口过程函数-----地址赋给lpfnWndProc成员变量
-
WNDPROC被定义为窗口过程函数的指针类型,窗口过程函数的格式必须与WNDPROC相同
-
__stdcall与__cedcl—这是两个不同的函数调用约定,定义了弹出栈的不同的约定,到底是谁弹出,让被调用函数还是调用函数弹出
-
printf用的是__cdecl调用约定,VS开发环境也是
-
Win32的函数都默认用__stdcall调用
第三个成员变量–cbClsExtra
- OS为系统每个窗口类管理一个WNDCLASS结构
- 这是类附加内存-----所有窗口共享
- 用于存储类的附加信息
- 一般就直接设置0
第四个----cbWndExtra
- 附加内存空间------------窗口附加内存
- 没有使用就设置0即可
第五个hInstance —窗口过程的实际句柄
第六个 hIcon 图标句柄
- VC++开发中,自定义菜单图标被命名为.rc----------资源脚本
- VC++中,资源是通过标识符ID来识别的
- ID是在resource.h的宏
- 他的lpIconname是一个指针,指向资源
第七个–hCursor是一个光标资源
第八个hbrBackground—窗口类的背景画刷句柄
第九个lpszMenuName----以空终止的字符串—指定菜单资源的名字
菜单不是一个窗口
第十个lpszClassName----以空终止的字符串—指定窗口类的名字
设计了新的型号的汽车,要起个名字
设计了新类型的窗口也要为该类型窗口取个名字
注册窗口类
- 相当于设计完后要government审批
- 批准后才能生产
- 调用RegisterClass注册
- 只有一个参数----上一步骤中所设计窗口类的对象的指针
创建窗口
- 用Create Window创建窗口
#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
- lpClassName 指定窗口类名称----------注册过的名字
- lpWindowName指定窗口名称---------标题栏名字
- dwStyle--------窗口样式,不同的汽车颜色---------可以指定WS_OVERLAPPEDWINDOW
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | //层叠的窗口,一个标题栏和一个边框
WS_CAPTION | //有标题栏的窗口
WS_SYSMENU | //标题栏上带有系统菜单的窗口口
WS_THICKFRAME | //有可调节边框
WS_MINIMIZEBOX | //有最小化
WS_MAXIMIZEBOX)
父窗口对子窗口有影响: 销毁,在父窗口被销毁前销毁
/符号的意义
“” 用于连接通常有两个方面:
①:在典型情况下用于转义连续多行的宏定义。(如上)
②:在逻辑上把下一行当作当前行的延续,它可以用于连接长字符串。(如下)
char a[] = "Hi! How are you? I am
fine, thank you!";
注意: 在 后面不能有其他字符,空格也不行!
显示及更新窗口
- 显示出来 ShowWindow
ShowWindow(
_In_ HWND hWnd,
_In_ int nCmdShow);
- nCmdShow------------窗口显示状态
更新窗口
- UpdateWindow
- The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window’s update region is not empty. The function sends a WM_PAINT message directly to the window procedure of the specified window, bypassing the application queue. If the update region is empty, no message is sent.
Copy to Clipboard
BOOL UpdateWindow(
HWND hWnd
);
消息循环
- 调用GetMessage
- 不断从消息队列取出消息,并进行相应。
GetMessageW(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax);
#ifdef UNICODE
- lpMsg----------指向MSG结构体
- hWnd-----------指定接受属于哪个窗口的消息,通常设置NULL,接受属于线程的所有窗口的消息
- wMsgFilterMin指定要获取消息的最小值----------常0
- wMsgFilterMax-------------------常0,接受所哟消息
GetMessage TranslateMessage DispatchMessage 和PeekMessage
- GetMessage TranslateMessage DispatchMessage 和PeekMessage
- Because the return value can be nonzero, zero, or -1, avoid code like this:
while (GetMessage( lpMsg, hWnd, 0, 0)) ...
- The possibility of a -1 return value in the case that hWnd is an invalid parameter (such as referring to a window that has already been destroyed) means that such code can lead to fatal application errors. Instead, use code like this:
在 hWnd 是无效参数的情况下返回值为 -1的可能性(例如引用已经被销毁的窗口)意味着这样的代码可能导致致命的应用程序错误。相反,应该这样使用代码:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
TranslateMessage
—将虚拟键消息转化为字符消息
- 字符消息被投递到调用线程的消息队列
- 调用getMessage的时候被取出
- 敲击键盘,产生
- 这两个消息附加参数-----虚拟键代码和扫描码
- 我们程序中只要得到某个字符的ASCII码
BOOL TranslateMessage(
CONST MSG *lpMsg
);
TranslateMessage
把KEYDOWN
和KEYUP
消息的组合转换为一条WM_CHAR
消息TranslateMessage
不修改源消息,只产生新消息投递到消息队列
DispatchMessage
----分派一个消息到窗口过程
- 分派一个消息到窗口过程
- 实际上是将消息回传给操作系统
LRESULT DispatchMessage( CONST MSG *lpMsg );
PeekMessage
函数功能
PeekMessage
是一个Windows API函数。该函数为一个消息检查线程消息队列
,并将该消息(如果存在)放于指定的结构。
函数声明
WINUSERAPI
BOOL
WINAPI
PeekMessageW(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax,
_In_ UINT wRemoveMsg);
第一个参数
lpMsg接收消息信息的MSG结构指针。
第二个参数
hWnd其消息被检查的窗口句柄。
第三个参数
wMsgFilterMin指定被检查的消息范围里的第一个消息。
第四个参数
wMsgFilterMax指定被检查的消息范围里的最后一个消息。
第五个参数
wRemoveMsg确定消息如何被处理。此参数可取下列值之一:
windows应用程序的消息处理机制
windows消息机制详解
编写窗口过程函数
匈牙利命名法
举例来说,表单的名称为form,那么在匈牙利命名法中可以简写为frm,则当表单变量名称为Switchboard时,变量全称应该为 frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单,同样,如果此变量类型为标签,那么就应命名成 lblSwitchboard。可以看出,匈牙利命名法非常便于记忆,而且使变量名非常清晰易懂,这样,增强了代码的可读性,方便各程序员之间相互交流代码。
变量属性
属性部分:
g_ 全局变量
c_ 常量
m_ c++类成员变量
s_ 静态变量
类型部分:
数组 a
指针 p
函数 fn
无效 v
句柄 h
长整型 l
布尔 b
浮点型(有时也指文件) f
双字 dw
字符串 sz
短整型 n
双精度浮点 d
计数 c(通常用cnt)
字符 ch(通常用c)
整型 i(通常用n)
字节 by
字 w
实型 r
无符号 u
描述部分:
最大 Max
最小 Min
初始化 Init
临时变量 T(或Temp)
源对象 Src
目的对象 Dest
MFC、句柄、控件及结构的命名规范:
Windows类型 样本变量;MFC类 样本变量
HWND hWnd; CWnd* pWnd;
HDLG hDlg; CDialog* pDlg;
HDC hDC; CDC* pDC;
HGDIOBJ hGdiObj; CGdiObject* pGdiObj;
HPEN hPen; CPen* pPen;
HBRUSH hBrush; CBrush* pBrush;
HFONT hFont; CFont* pFont;
HBITMAP hBitmap; CBitmap* pBitmap;
HPALETTE hPaltte; CPalette* pPalette;
HRGN hRgn; CRgn* pRgn;
HMENU hMenu; CMenu* pMenu;
HWND hCtl; CState* pState;
HWND hCtl; CButton* pButton;
HWND hCtl; CEdit* pEdit;
HWND hCtl; CListBox* pListBox;
HWND hCtl; CComboBox* pComboBox;
HWND hCtl; CScrollBar* pScrollBar;
HSZ hszStr; CString pStr;
POINT pt; CPoint pt;
SIZE size; CSize size;
RECT rect; CRect rect;
一般前缀命名规范:
前缀&类型&实例
C 类或结构 CDocument,CPrintInfo
m_ 成员变量 m_pDoc,m_nCustomers
变量命名规范:
前缀&类型&描述&实例
ch char 8位字符 chGrade
ch TCHAR 如果_UNICODE定义,则为16位字符 chName
b BOOL 布尔值 bEnable
n int 整型(其大小依赖于操作系统) nLength
u UINT 无符号值(其大小依赖于操作系统) uHeight
w WORD 16位无符号值 wPos
l LONG 32位有符号整型 lOffset
dw DWORD 32位无符号整型 dwRange
p * 指针 pDoc
lp FAR* 远指针 lpszName
lpsz LPSTR 32位字符串指针 lpszName
lpsz LPCSTR 32位常量字符串指针 lpszName
lpsz LPCTSTR 如果_UNICODE定义,则为32位常量字符串指针 lpszName
h handle Windows对象句柄 hWnd
lpfn callback 指向CALLBACK函数的远指针
前缀_符号类型:
前缀_符号类型实例&范围
IDR_ 不同类型的多个资源共享标识 IDR_MAIINFRAME 1~0x6FFF
IDD_ 对话框资源 IDD_SPELL_CHECK 1~0x6FFF
HIDD_ 对话框资源的Help上下文 HIDD_SPELL_CHECK 0x20001~0x26FF
IDB_ 位图资源 IDB_COMPANY_LOGO 1~0x6FFF
IDC_ 光标资源 IDC_PENCIL 1~0x6FFF
IDI_ 图标资源 IDI_NOTEPAD 1~0x6FFF
ID_ 来自菜单项或工具栏的命令 ID_TOOLS_SPELLING 0x8000~0xDFFF
HID_ 命令Help上下文 HID_TOOLS_SPELLING 0x18000~0x1DFFF
IDP_ 消息框提示 IDP_INVALID_PARTNO 8~0xDEEF
HIDP_ 消息框Help上下文 HIDP_INVALID_PARTNO 0x30008~0x3DEFF
IDS_ 串资源 IDS_COPYRIGHT 1~0x7EEF
IDC_ 对话框内的控件 IDC_RECALC 8~0xDEEF
Microsoft MFC宏命名规范:
名称&类型
_AFXDLL 唯一的动态连接库(Dynamic Link Library,DLL)版本
_ALPHA 仅编译DEC Alpha处理器
_DEBUG 包括诊断的调试版本
_MBCS 编译多字节字符集
_UNICODE 在一个应用程序中打开Unicode
AFXAPI MFC提供的函数
CALLBACK 通过指针回调的函数
库标识符命名法:
标识符&值和含义
u ANSI(N)或Unicode(U)
d 调试或发行:D = 调试;忽略标识符为发行。
静态库版本命名规范:
库&描述
NAFXCWD.LIB 调试版本:MFC静态连接库
NAFXCW.LIB 发行版本:MFC静态连接库
UAFXCWD.LIB 调试版本:具有Unicode支持的MFC静态连接库
UAFXCW.LIB 发行版本:具有Unicode支持的MFC静态连接库
动态连接库命名规范:
名称&类型
_AFXDLL 唯一的动态连接库(DLL)版本
WINAPI Windows所提供的函数
Windows.h中新的命名规范:
类型&定义描述
WINAPI 使用在API声明中的FAR PASCAL位置,如果正在编写一个具有导出API人口点的DLL,则可以在自己的API中使用该类型
CALLBACK 使用在应用程序回叫例程,如窗口和对话框过程中的FAR PASCAL的位置
LPCSTR 与LPSTR相同,只是LPCSTR用于只读串指针,其定义类似(const char FAR*)
UINT 可移植的无符号整型类型,其大小由主机环境决定(对于Windows NT和Windows 9x为32位);它是unsigned int的同义词
LRESULT 窗口程序返回值的类型
LPARAM 声明lParam所使用的类型,lParam是窗口程序的第四个参数
WPARAM 声明wParam所使用的类型,wParam是窗口程序的第三个参数
LPVOID 一般指针类型,与(void *)相同,可以用来代替LPSTR
????博主昵称:
一拳必胜客
????博主寄语:欢迎点赞收藏关注哦,一起成为朋友一起成长;
特别鸣谢:木芯工作室 、Ivan from Russia
最后
以上就是细腻老师为你收集整理的WINDOWS核心编程--Windows程序内部运行机制windows程序内部运行机制WinMain函数窗口的创建注册窗口类创建窗口显示及更新窗口更新窗口消息循环windows应用程序的消息处理机制编写窗口过程函数匈牙利命名法MFC、句柄、控件及结构的命名规范:一般前缀命名规范:Microsoft MFC宏命名规范:库标识符命名法:静态库版本命名规范:动态连接库命名规范:的全部内容,希望文章能够帮你解决WINDOWS核心编程--Windows程序内部运行机制windows程序内部运行机制WinMain函数窗口的创建注册窗口类创建窗口显示及更新窗口更新窗口消息循环windows应用程序的消息处理机制编写窗口过程函数匈牙利命名法MFC、句柄、控件及结构的命名规范:一般前缀命名规范:Microsoft MFC宏命名规范:库标识符命名法:静态库版本命名规范:动态连接库命名规范:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复