C++ win32编程 02 常见消息

02 常见消息

1 打印消息相关信息

1.1 将消息内容转化为字符串

第一步: 定义字符串变量,用来保存转化后的消息

wchar_t szInfo[300];  //定义消息内容变量

第二步:用宽字符格式化函数转化消息内容\

wsprintf(szInfo, "hWnd=%d\tuMsg=%d\twParam=%d, lParam=%d", 
         		  hWnd, 	uMsg, 	wParam, 	lParam);

这里说明一下,为什么四个参数都可以直接以16进制形式进行格式化

参数类型本质
hWndHWND结构体指针
uMsgUINTunsigned int 无符号整型
wParamWPARAMtypedef UINT_PTR WPARAM;
lParamLPARAMtypedef LONG_PTR LPARAM;

不同的消息,wParam 与 lParam会有不同的意义

2 窗体创建消息

消息名: WM_CREATE

触发对象: 当调用CreateWindow 或 CreateWindowEx创建窗体完后触发

触发时机: 调用以上两个函数完毕后立即触发,此时窗体还未显示

附加参数意义:

wParam: 没用到

lParam: 一个指向 CREATESTRUCT 结构体的指针,类型为LPCREATESTRUCT

注意: 按照一般命名规则,类型名前加LP表示指针类型

CREATESTRUCT 结构体成员

typedef struct tagCREATESTRUCT {
  LPVOID    lpCreateParams;		//指向将被用于创建窗口的数据的指针
  HINSTANCE hInstance;			//窗体所属应用程序句柄
  HMENU     hMenu;				//窗体菜单句柄
  HWND      hwndParent;			//窗体父窗体句柄
  int       cy;					//窗体高度
  int       cx;					//窗体宽度
  int       y;					//窗体左上角y坐标
  int       x;					//窗体左上角x坐标
  LONG      style;				//窗体显示风格
  LPCTSTR   lpszName;			//指向以结束符('\0')表示结尾的字符串,指定了新窗口的名字。
  LPCTSTR   lpszClass;			//指向以结束符('\0')表示结尾的字符串,指定了新窗口的类名
  DWORD     dwExStyle;			//窗体的扩展样式
} CREATESTRUCT, *LPCREATESTRUCT;

本例测试代码:

case WM_CREATE:
	{

		wchar_t szcsInfo[300];
		LPCREATESTRUCT	lpcs = (LPCREATESTRUCT)lParam;
		wsprintf(szcsInfo, L"窗体类名: %s, 窗体名称: %s\n", 
                 			lpcs->lpszClass, lpcs->lpszName);
		OutputDebugString(szcsInfo);
		break;
	}

运行效果截图:

img

注意:

lParam是一个结构体指针,在使用时注意强制转化为相应的类型

LPCREATESTRUCT	lpcs = (LPCREATESTRUCT)lParam;

结构体类型: CREATESTRUCT

相应的结构体类型指针: LPCREATESTRUCT

在看帮助文档的时候,注意看清楚

img

3 窗口关闭消息

消息名: WM_CLOSE

触发对象: 点击窗口右上角的关闭(X)按钮

触发时机:点击后发送

wParam: 没用(0)

lParam: 没用(0)

示例代码:

case WM_CLOSE: //处理关闭按钮消息
{
    int btnValue = MessageBox(hWnd, L"是否确认关闭窗口?", L"温馨提示", MB_YESNO);
    if (btnValue == IDYES){
        DestroyWindow(hWnd); //销毁窗口
        break;
    }
    else{
        return 1;
    }
}

解析:

按下关闭按钮会弹出对话框,确认是否关闭

int btnValue = MessageBox(hWnd, L"是否确认关闭窗口?", L"温馨提示", MB_YESNO);

当弹出对话框按下确认按钮时,将会进入关闭窗口流程

if (btnValue == IDYES){
    DestroyWindow(hWnd); //销毁窗口
    break;
}

关闭主程序与关闭窗口是两个不同的事情

这个我们在上节课已经学过,关闭窗口只需要调用DestroyWindow即可

DestroyWindow(hWnd); //销毁窗口

但是关闭主程序还需要发送退出消息循环的命令

PostQuitMessage(0);

如果点击关闭然后点击取消按钮,即不想关闭,我们需要将关闭窗体的消息从消息对列清楚出去

else{
    return 1;
}

当我们将消息交给系统处理程序的代码写在switch之外的时候,这个地方必须要return 一下,以防止关闭消息被系统处理程序重新处理一边,导致的窗体关闭

即:我们不主动处理窗口关闭事件,只要这个消息流入系统消息处理函数,系统也会帮我们关闭窗口.

但是如果关闭这个窗口后想要进一步关闭主程序,就必须在WM_DESTROY消息中发送退出消息循环的命令

PostQuitMessage(0);来结束程序的进程

如果系统消息处理函数是写在switch的default分支中的,则只需要直接break即可实现不关闭窗口的效果

测试代码如下:

LRESULT CALLBACK fWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg){
	case WM_CLOSE: //处理关闭按钮消息
	{
		int btnValue = MessageBox(hWnd, L"是否确认关闭窗口?", L"温馨提示", MB_YESNO);
		if (btnValue == IDYES){
			DestroyWindow(hWnd); //销毁窗口
		}
		break;
	}
	case WM_DESTROY:
		PostQuitMessage(0); //发送退出消息
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 1;
}				

特别要注意:

(1) 在没有调用DestroyWindow函数前,窗体关闭过程可以中止,一旦调用了DestroyWindow,窗口关闭就无法逆转

因此关闭窗口的关键在于调用DestroyWindow函数的时机

(2) 再强调一下关闭窗口与关闭程序是两个不同的概念,关闭窗口只需要DestroyWindow即可,关闭程序要调用PostQuitMessage函数

4 鼠标消息

4.1 鼠标左键消息
消息名称消息含义
WM_LBUTTONDOWN鼠标左键按下(一个动作,不包含按下的状态)
WM_LBUTTONUP鼠标左键松开(弹起一瞬间的动作)
WM_LBUTTONDBLCLK鼠标左键双击动作(动作完成的一瞬间)
组合键

wParam的可能取值:

含义
MK_CONTROLCtrl键处于按下状态
MK_LBUTTON左键处于按下状态
MK_MBUTTON鼠标中键(滚轮键)处于按下状态
MK_RBUTTON鼠标右键处于按下状态
MK_SHIFTshift键处于按下状态
MK_XBUTTON1
MK_XBUTTON12

判断方法是对可能的取值做与运算,结果为True则按下了,否则没有按下

如判断按下鼠标左键时是否已经按下了CTRL键

case WM_LBUTTONDOWN:
    if (wParam & MK_CONTROL)
    {
    	SetWindowText(hWnd,L"同时按下Ctrl+鼠标左键");
    }
    break;

注意:

用可能的取值去与wParam做&(按位与)运算来判断是否成立

又如: 判断ctrl + shift + 鼠标左键

case WM_LBUTTONDOWN:
    if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT)){
        SetWindowText(hWnd,L"同时按下Ctrl + Shift + 鼠标左键");
    }
    break;

注意:

(1) WM_LBUTTONDWON 消息下MK_LBUTTON没有意义

(2) 在处理了WM_LBUTTONDOWN消息后直接处理WM_LBUTTONDBLCLK 时会导致双击消息无法获得响应

解决方法:

在WM_LBUTTONDOWN对本次的点击时间与上次的点击时间做差,如果差值在指定时间内,则为双击,不在指定时间为则为单击

获取时间的函数:GetMessageTime()函数来获取当次消息发送的时间

函数原型

LONG WINAPI GetMessageTime(void);

返回值是一个表示时间的长整型.这个时间与系统时间无关,从0开始,到超过取值范围后会从0重新开始

因此,如果要判断时间差,需要判断第二个时间>第一个时间

示例代码:

case WM_LBUTTONDOWN:
{
    LONG clickTime = GetMessageTime();
    if (lastClickTime == 0 || clickTime - lastClickTime > 500){
        SetWindowText(hWnd, L"鼠标左键");
    }
    else{
        SetWindowText(hWnd, L"双击鼠标左键");
    }
    lastClickTime = clickTime;
    break;
}

注意: 为简化程序, 本例没有对时间做判断

鼠标的位置信息

lParam中包含了鼠标的位置信息,高位表示y坐标,低位表示x坐标

注意: 坐标是鼠标在窗体客户区的位置 ,不是以屏幕作为参考的坐标位置

有两种方法获取鼠标的x,y坐标

方法一:

int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);

注意:此方法要求包含头文件:Windowsx.h

方法二:

int x = LOWORD(lParam);
int y = HIWORD(lParam);

示例代码:

case WM_LBUTTONDOWN:
{
    //以下显示鼠标位置
    int x2 = LOWORD(lParam);
    int y2 = HIWORD(lParam);
    int x1 = GET_X_LPARAM(lParam);
    int y1 = GET_Y_LPARAM(lParam);
    wchar_t mousePosInfo[100];
    wsprintf(mousePosInfo, L"方法一: 鼠标的x坐标:%d, y坐标:%d\n 方法二: 鼠标的x坐标:%d, y坐标:%d\n",
             x1, y1, x2, y2);
    OutputDebugString(mousePosInfo);
    break;
}

运行结果:

img

4.2 其他鼠标消息
消息名消息含义
WM_RBUTTONDOWN右键按下
WM_RBUTTONUP右键松开(弹起)
WM_RBUTTONDBLCLK右键双击
WM_MBUTTONDOWN中键(滚轮)按下
WM_MBUTTONUP中键(滚轮)松开
WM_MBUTTONDBLCLK中键(滚轮)双击
WM_MOUSEMOVE鼠标移动

附加参数wParam与lParam的意义与用法同左键,不再展开

5 键盘事件

5.1 单个按键按下

消息名称: WM_KEYDOWN

wParam可能的取值, 常用按键表

含义
VK_LBUTTON 0x01鼠标左键按下状态
VK_RBUTTON 0x02鼠标右键按下状态
VK_CANCEL 0x03Ctrl + Break
VK_MBUTTON 0x04鼠标中键
VK_XBUTTON1 0x05X1 mouse button
VK_XBUTTON2 0x06X2 mouse button
VK_BACK 0x08BackSpace
VK_TAB 0x09TAB键
VK_CLEAR 0x0CCLEAR key
VK_RETURN 0x0DENTER key 回车
VK_SHIFT 0x10SHIFT key
VK_CONTROL 0x11CTRL key
VK_MENU 0x12ALT key
VK_PAUSE 0x13PAUSE key
VK_CAPITAL 0x14CAPS LOCK key
VK_KANA 0x15IME Kana mode 别问,问就是不知道
VK_HANGUEL 0x15IME Hanguel mode (maintained for compatibility; use VK_HANGUL) 别问,问就是不知道
VK_HANGUL 0x15IME Hangul mode 别问,问就是不知道
VK_JUNJA 0x17IME Junja mode 别问,问就是不知道
VK_FINAL 0x18IME final mode 别问,问就是不知道
VK_HANJA 0x19IME Hanja mode 别问,问就是不知道
VK_KANJI 0x19IME Kanji mode 别问,问就是不知道
VK_ESCAPE 0x1BESC key
VK_CONVERT 0x1CIME convert 别问,问就是不知道
VK_NONCONVERT 0x1DIME nonconvert 别问,问就是不知道
VK_ACCEPT 0x1EIME accept 别问,问就是不知道
VK_MODECHANGE 0x1FIME mode change request 别问,问就是不知道
VK_SPACE 0x20SPACEBAR 空格键
VK_PRIOR 0x21PAGE UP key
VK_NEXT 0x22PAGE DOWN key
VK_END 0x23END key
VK_HOME 0x24HOME key
VK_LEFT 0x25LEFT ARROW key 方向左
VK_UP 0x26UP ARROW key 方向上
VK_RIGHT 0x27RIGHT ARROW key 方向右
VK_DOWN 0x28DOWN ARROW key 方向下
VK_SELECT 0x29SELECT key
VK_PRINT 0x2APRINT key
VK_EXECUTE 0x2BEXECUTE key
VK_SNAPSHOT 0x2CPRINT SCREEN key
VK_INSERT 0x2DINS key
VK_DELETE 0x2EDEL key
VK_HELP 0x2FHELP key
0x300 key 大键数字0-9
0x311 key
0x322 key
0x333 key
0x344 key
0x355 key
0x366 key
0x377 key
0x388 key
0x399 key
0x41A key 字母A-Z
0x42B key
0x43C key
0x44D key
0x45E key
0x46F key
0x47G key
0x48H key
0x49I key
0x4AJ key
0x4BK key
0x4CL key
0x4DM key
0x4EN key
0x4FO key
0x50P key
0x51Q key
0x52R key
0x53S key
0x54T key
0x55U key
0x56V key
0x57W key
0x58X key
0x59Y key
0x5AZ key
VK_LWIN 0x5BLeft Windows key (Natural keyboard) 左win键
VK_RWIN 0x5CRight Windows key (Natural keyboard) 右win键
VK_APPS 0x5DApplications key (Natural keyboard)
VK_SLEEP 0x5FComputer Sleep key
VK_NUMPAD0 0x60Numeric keypad 0 key 小键数字0-9
VK_NUMPAD1 0x61Numeric keypad 1 key
VK_NUMPAD2 0x62Numeric keypad 2 key
VK_NUMPAD3 0x63Numeric keypad 3 key
VK_NUMPAD4 0x64Numeric keypad 4 key
VK_NUMPAD5 0x65Numeric keypad 5 key
VK_NUMPAD6 0x66Numeric keypad 6 key
VK_NUMPAD7 0x67Numeric keypad 7 key
VK_NUMPAD8 0x68Numeric keypad 8 key
VK_NUMPAD9 0x69Numeric keypad 9 key
VK_MULTIPLY 0x6AMultiply key 小键盘乘号
VK_ADD 0x6BAdd key 小键盘加号
VK_SEPARATOR 0x6CSeparator key 小键盘除号
VK_SUBTRACT 0x6DSubtract key 小键盘减号
VK_DECIMAL 0x6EDecimal key 小键盘.键
VK_F1 0x70F1 key 功能键F1-F24 (为什么我的键盘只到F12的)
VK_F2 0x71F2 key
VK_F3 0x72F3 key
VK_F4 0x73F4 key
VK_F5 0x74F5 key
VK_F6 0x75F6 key
VK_F7 0x76F7 key
VK_F8 0x77F8 key
VK_F9 0x78F9 key
VK_F10 0x79F10 key
VK_F11 0x7AF11 key
VK_F12 0x7BF12 key
VK_F13 0x7CF13 key
VK_F14 0x7DF14 key
VK_F15 0x7EF15 key
VK_F16 0x7FF16 key
VK_F17 0x80F17 key
VK_F18 0x81F18 key
VK_F19 0x82F19 key
VK_F20 0x83F20 key
VK_F21 0x84F21 key
VK_F22 0x85F22 key
VK_F23 0x86F23 key
VK_F24 0x87F24 key
VK_NUMLOCK 0x90NUM LOCK key NumLock键
- 0x97-9FUnassigned
VK_LSHIFT 0xA0Left SHIFT key 左Shift
VK_RSHIFT 0xA1Right SHIFT key 右Shfit
VK_LCONTROL 0xA2Left CONTROL key 左 Ctrl
VK_RCONTROL 0xA3Right CONTROL key 右Ctrl
VK_LMENU 0xA4Left MENU key 左Alt
VK_RMENU 0xA5Right MENU key 右Alt

示例代码

case WM_KEYDOWN:
{
    switch (wParam){
        case 0x30:
            SetWindowText(hWnd, L"0"); //按下了大键盘区的数字0键
            break;
    }
}

注意:

WM_KEYDOWN 消息不能捕获一些特殊的系统按键,如ALT

如果在实际应用中发现没有如期捕获到一些特殊的按键,可能是系统按键,需要用

WM_SYSKEYDOWN消息来捕获这些按键

该事件的附加参数wParam, lParam与WM_KEYDOWN消息的内容是一样的,就不再展开了

示例代码: 捕获ALT键

case WM_SYSKEYDOWN:
        {
            switch (wParam)
            {
                case VK_MENU:
                {
                    OutputDebugString(L"ALT\n");
                    return DefWindowProc(hWnd, uMsg, wParam, lParam);
                }
            }
        }

注意:

使用WM_SYSKEYDOWN 捕获系统按键后要交还给系统处理函数,否则有可能引起一些莫名其妙的错误(这里指我也不知道为什么会有什么后果的错误)

5.2 组合按键检测

当我们需要判断一个按键

用函数GetKeyState 与 GetAsyncKeyState来判断指定按键的状态

两者的区别在于键盘消息生成时的状态与当前调用函数时的按键状态

函数原型:

SHORT WINAPI GetKeyState(
  _In_  int nVirtKey
);

参数: 按键的虚拟值,即上表中的内容

返回值: SHORT

返回值

高位为1时表示按键按下了,其他值为没有按下

低位为1时表示锁定状态,其他值为没有锁定(如CapsLock键,NumsLock键等)

示例代码: Ctrl+F1响应

case VK_F1:                                   //F1键检测
{          
    SHORT bCtrl = GetKeyState(VK_CONTROL);
    if (bCtrl >> 15)
    {
        OutputDebugString(L"CTRL+F1\n");
    }
    break;
}

示例代码: 大小写字母

case 0x41:
{
    SHORT bCapsLock = GetKeyState(VK_CAPITAL);
    if (bCapsLock & 1)
    {
        //大写锁定状态输出A
        OutputDebugString(L"A");
    }
    else
    {
        //没有大写锁定状态输出a
        OutputDebugString(L"a");
    }
    break;
}

Alt+的组合暂时搞不定_

6 字符消息

消息名称: WM_CHAR

消息发送是时机:

(1) 按下字母,数字键

(2) 调用了TranslateMessage函数

wParam: 字符

lParam: 同其他按键附加信息

示例代码: 输出按键字符

case WM_CHAR:
{
    wchar_t charInfo[100];
    wsprintf(charInfo, L"按下的字符:%c", (char)wParam);
    SetWindowText(hWnd, charInfo);
}

img

如果不开启TranslateMessage 则无法生成WM_CHAR消息

7 绘图消息

消息名: WM_PAINT

消息发送时机: 当系统或其他应用程序请求绘制应用程序窗口的一部分时

wParam: 没用

lParam: 没用

示例代码:

case WM_PAINT:
{
    //绘图刷子结构体
    PAINTSTRUCT ps;
    //绘图句柄
    //第一个参数: 需要绘图的窗口句柄, 第二个参数: 绘图刷子结构体 返回值: 绘图句柄
    HDC hDc = BeginPaint(hWnd, &ps); //开始绘图    
    Rectangle(hDc, 0,0, 200, 200); //画一个矩形, 后面四参数依次是:左上x,左上y,宽, 高
    Ellipse(hDc,0,0,200,200);//椭圆(圆可以看成特殊的椭圆)
    EndPaint(hWnd, &ps);  //结束绘图
}

运行效果:

img

这个消息了解一下就好了.

8 其他有用的知识

8.1 在程序运行过程中观察变量动态

第一步:在需要监视变量的地方设置断点

img

第二步: 开启调试

img

第三步: 点击下方监视窗口

img

如果没有监视窗口,可以点菜单栏: 调试->窗口->监视窗口(Ctrl+Alt+W) 然后按1或2或3或4来选择监视窗口

img

第四步:将变量加入监视窗口

(1) 选中断点处的变量名

(2) 按住鼠标不要松开

(3)将变量名拖动到下方监视窗口

![img][10]

8.2 查看其他应用程序的窗口类名与窗口标题

第一步: 打开spy窗口

![img][11]

第二步: 打开偷窥窗口

![img][12]

![img][13]

第三步:点击要查看的应用程序窗口

![img][14]

效果图:

![img][15]

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Win32 VLC 播放器是一个基于C语言的视频和音频播放器,它使用了Win32 API来控制窗口、消息处理和绘制图像等功能。VLC播放器是一个流行的开源多媒体框架,可以播放各种音频和视频格式。 在Win32 VLC 播放器中,主要使用了C语言进行编程。C语言是一种底层语言,具有高效的性能和灵活的操作方式,非常适合用于开发多媒体应用。 Win32 VLC播放器的实现可以分为几个主要步骤:首先,需要使用Win32 API创建一个窗口,用于显示视频画面和控制播放器的界面。然后,通过使用VLC的API,可以加载音频和视频文件,并进行播放、暂停、停止等操作。同时,还可以设置音量、播放速度等参数。 在播放器界面中,可以使用各种Win32 API函数和消息处理机制来实现用户与播放器的交互。比如,在窗口中添加按钮、滑块等控件,通过接收按钮点击和滑块滑动的消息,来控制播放器的行为。 最后,需要在程序退出时释放所使用的资源,关闭视频和音频的播放,销毁窗口等。 总的来说,Win32 VLC播放器是一个基于C语言的多媒体应用程序,通过使用Win32 API和VLC框架,可以实现视频和音频的播放、控制及界面交互等功能。它的优势在于使用底层语言来实现,具有高效性能和灵活的操作方式。 ### 回答2: Win32 VLC播放器是一个基于C语言开发的,可以在Windows环境下运行的视频播放器。它基于VLC媒体框架,具有强大的功能和广泛的兼容性,可以播放多种音视频格式,包括常见的MP4、AVI、MKV等等。 Win32 VLC播放器使用C语言开发,具有较高的效率和性能。C语言是一种结构化编程语言,非常适合编写底层系统程序和驱动。VLC播放器需要与底层的操作系统进行交互,控制音视频的输入输出,处理静音、快进、快退等功能,使用C语言可以更加方便地实现这些功能。 Win32 VLC播放器还支持插件扩展,开发者可以通过C语言编写自己的插件,添加更多的功能和特性。这样,用户可以根据自己的需求来定制和扩展播放器,提升用户体验。 总之,Win32 VLC播放器是一个基于C语言开发,功能强大且高效的视频播放器。它支持多种音视频格式,可以在Windows环境下运行,并且可以通过插件扩展来满足用户的多样化需求。 ### 回答3: Win32 VLC 播放器是指针对 Windows 平台开发的一个基于C语言的多媒体播放器软件。VLC 播放器是由 VideoLAN 团队开发的开源播放器,其如今在全球范围内都广泛使用。 Win32Windows操作系统的一个应用程序编程接口(API),主要用于开发基于 Windows 平台的应用程序,包括桌面应用、游戏等。C语言是一种通用的高级编程语言,被广泛应用于各种操作系统和硬件平台上的软件开发。 利用Win32 API对VLC播放器进行开发,可以实现多媒体文件的播放、暂停、停止、快进、倒带等操作,并且可以处理各种常见的音视频格式,如MP3、MP4、AVI等。开发者可根据自己的需求,通过调用Win32 API函数来实现与用户交互、图形界面设计、文件操作等功能,从而实现一个功能完善的VLC播放器。 开发Win32 VLC播放器,需要具备熟练的C语言编程技巧、对Win32 API的熟悉以及对多媒体编码原理的理解。在开发过程中,可以使用各种资源管理和线程控制方法,来提高程序的并发性和稳定性。同时,需要做好错误处理和异常处理,保证程序的可靠性和用户体验。 Win32 VLC 播放器的开发不仅可以让用户在Windows平台上播放各种视频和音频文件,还可以为用户提供个性化的体验,如字幕支持、窗口大小调节、设置播放列表等功能。总体来说,Win32 VLC 播放器的开发对于提高用户的多媒体播放体验以及开源软件的推广都具有积极作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的章老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值