Win32概述
一、Win32概述
新建Win32项目
新建项目,Win32项目,空项目,不勾选安全开发周期
右键解决方案名称,新建项,C++文件
Windows四大模块程序
控制台程序,窗口程序,动态库(dll), 静态库(lib)
Win32入口函数
windows是基于C,C++,又想有自己的数据类型,所以重定义,来区别C语言,或者达到顾名思义的效果
(HINSTANCE,LPSTR)
特性:
如果不认识,先转到定义看这个类型
大写H开头的叫句柄,(HINSTANCE)
大写P,LP开头,表示指针
封装信息:HINSTANCE 就是void*,看不到具体类型
1 2 3 4 5 6 7 8 9 10 11 #include <windows.h> int WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MessageBox (0 , "Hello" , 0 , 0 ); return 0 ; }
MessageBox
MessageBox(窗口句柄,"文本","标题",类别);
1 MessageBox (nullptr , "Hello" , "class1" ,MB_YESNOCANCEL | MB_ICONWARNING);
MB_OK 确定按钮
MB_YESNOCANCEL 是,否,取消
1 2 3 if (IDYES == MessageBox (0 , ptc, 0 , MB_YESNO)) { }
字符集
项目菜单->最后的属性->配置属性->常规->项目默认值->设置字符集
Unicode 宽字节字符集
1 2 3 4 5 char c = 'a' ; char *pc = "abcd" ; wchar_t wc = 'a' ; wchar_t *pwc = L"abcd"
为了方便,映入TCHAR来调整,多字节和宽字节
1 2 3 4 5 6 7 #include <tchar.h> TCHAR tc = 'a' ; TCHAR *ptc = &tc; ptc = _T("abcd" ); _tcslen(ptc);
MessageBox的类型
如果有函数后缀上有大写的A或W,说明有参数是多字节或宽字节
1 2 3 MessageBox (0 , ptc, 0 , 0 );MessageBoxA (0 , "abc" , 0 , 0 ); MessageBoxW (0 , L"abc" , 0 , 0 );
Windows学习重点
搞清楚函数是干嘛的
参数是什么意思
wav格式的音乐播放
PlaySound函数
1 2 3 4 5 6 #pragma comment (lib,"Winmm.lib" ) PlaySound (_T("2.wav" ), nullptr , SND_LOOP | SND_FILENAME | SND_ASYNC);
mp3格式音乐播放
mciSendString
1 2 3 4 mciSendString (_T("open 长安忆—双笙翻唱.mp3 alias abc" ), nullptr , 0 , nullptr );
二、Win32框架
打开项目->不勾选空项目,默认打开。
CALLBACK 没有实际代码含义,用作解释
1 2 3 4 5 6 7 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;MSG msg; LoadString (hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString (hInstance, IDC_CLASS02, szWindowClass, MAX_LOADSTRING);
试图-->资源视图
可以看窗口,可视化编程
注册窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ATOM MyRegisterClass (HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof (WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0 ; wcex.cbWndExtra = 0 ; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_CLASS02)); wcex.hCursor = LoadCursor (NULL , IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1 ); wcex.lpszMenuName = MAKEINTRESOURCE (IDC_CLASS02); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon (wcex.hInstance, MAKEINTRESOURCE (IDI_SMALL)); return RegisterClassEx (&wcex); }
应用程序初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 BOOL InitInstance (HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; hWnd = CreateWindow (szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0 , CW_USEDEFAULT, 0 , NULL , NULL , hInstance, NULL ); if (!hWnd) { return FALSE; } ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); return TRUE; }
加载快捷键
1 hAccelTable = LoadAccelerators (hInstance,MAKEINTRESOURCE (IDC_CLASS02));
Win32框架:
入口函数
窗口注册类信息
窗口创建
窗口显示
窗口更新
消息循环
入口函数返回
三、消息框架
windows操作系统最大的特色是良好的用户交互性
1、产生消息 2、传递消息 3、处理消息
消息类MSG
1 2 3 4 5 6 7 8 9 10 11 typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; #ifdef _MAC DWORD lPrivate; #endif } MSG;
windows操作系统为每一个正在运行的应用程序维护一个消息队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 while (GetMessage (&msg, NULL , 0 , 0 )) { if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } ZeroMemory (&msg, sizeof (msg));while (msg.message != WM_QUIT) { if (PeekMessage (&msg, NULL , 0 , 0 , PM_REMOVE)) { if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } }
SendMessage(句柄,消息,0,0) 投递消息给窗口,可以理解为递归
PostMessage(句柄,消息,0,0)
投递消息到窗口的消息队列,可以理解为排队
1 2 SendMessage (hWnd, WM_KEYDOWN, 0 , 0 );PostMessage (hWnd, WM_KEYDOWN, 0 , 0 );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 switch (message){ case WM_COMMAND: wmId = LOWORD (wParam); wmEvent = HIWORD (wParam); switch (wmId) { case IDM_ABOUT: DialogBox (hInst, MAKEINTRESOURCE (IDD_ABOUTBOX), hWnd, About); break ; case IDM_EXIT: DestroyWindow (hWnd); break ; default : return DefWindowProc (hWnd, message, wParam, lParam); } break ; case WM_PAINT: hdc = BeginPaint (hWnd, &ps); EndPaint (hWnd, &ps); break ; case WM_DESTROY: PostQuitMessage (0 ); break ; default : return DefWindowProc (hWnd, message, wParam, lParam); }
其他消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 case WM_CREATE: break ;case WM_ACTIVATE: switch (wParam) { case WA_CLICKACTIVE: break ; case WA_ACTIVE: break ; case WA_INACTIVE: break ; } case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: break ; } break ;
四、重要消息
按键消息
1 2 3 4 5 6 7 8 9 10 11 12 case WM_KEYDOWN: switch (wParam) { case VK_F1: MessageBox (0 , _T("f1" ), 00 , 0 ); break ; case VK_MENU: break ; case 'A' : MessageBox (0 , _T("A" ), 0 , 0 ); break ; }
char消息要经过TranslateMessage(&msg); 来翻译消息
1 2 3 4 5 6 7 8 9 10 11 12 13 case WM_CHAR: switch (wParam) { case 'A' : MessageBox (0 , _T("A" ), 0 , 0 ); break ; case 'b' : MessageBox (0 , _T("b" ), 0 , 0 ); break ; default : break ; } break ;
系统按键按下:
1、按下alt键或f10
2、alt加组合键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 case WM_SYSKEYDOWN: switch (wParam) { case VK_MENU: MessageBox (0 , _T("alt" ), 0 , 0 ); break ; case VK_F10: MessageBox (0 , _T("f10" ), 0 , 0 ); break ; case 'A' : MessageBox (0 , _T("alt +A" ), 0 , 0 ); break ; } break ;
注册热键还可以用RigisterHotKey()函数,在Create窗口的时候
鼠标消息
辅助消息里,鼠标相关的在lParam,其他的在wParam
1 2 3 4 5 6 7 8 9 10 11 12 13 case WM_LBUTTONDOWN: short x = LOWORD (lParam); short y = HIWORD (lParam); break ; case WM_LBUTTONUP: break ; case WM_LBUTTONDBLCLK: break ; case WM_MOUSEMOVE: break ; case WM_MOUSEWHEEL: short b = HIWORD (wParam); break ;
计时器消息
1、设置计时器
2、响应计时器
3、销毁计时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 case WM_CREATE: SetTimer (hWnd, 1001 , 1000 , nullptr ); SetTimer (hWnd, 1002 , 1000 , (TIMERPROC)aaa); break ; case WM_TIMER: switch (wParam) { case 1001 : KillTimer (hWnd,1001 ); break ; } break ;
五、菜单
从编程的角度来分类:静态菜单,动态菜单,快捷菜单
静态菜单:在菜单资源编辑器中预先编辑好的
动态菜单:在程序运行的过程中通过代码生成
快捷菜单:是前两种菜单的组合,预先编辑好,然后在运行时动态显示
静态菜单
对于菜单而言:可以理解为二位数组
菜单里面的每一个元素都是一个菜单项,菜单项包含两个最基本的要素
1、菜单项名字
2、菜单项的唯一id号
每一个元素还可以是嵌套的子菜单数组
1 2 3 4 5 6 7 8 9 case WM_COMMAND: wmId = LOWORD (wParam); wmEvent = HIWORD (wParam); switch (wmId) { case ID_my1: MessageBox (0 , 0 , 0 , 0 ); break ;
设置快捷键
在取名的时候(&C)可以设置快捷键
或者在资源视图里,Accelerator文件夹的IDC_..的那个文件里进行设置
菜单分隔符可以在取名的时候输入-生成
添加新菜单
右键Menu文件夹,添加菜单就好了
然后是加载菜单
1 2 wcex.lpszMenuName = MAKEINTRESOURCE (IDC_CLASS02);
或者在创建窗口的时候改
1 2 3 4 5 6 7 8 9 10 11 12 13 HMENU h1 = LoadMenu (hInstance, MAKEINTRESOURCE (IDC_CLASS02)); hWnd = CreateWindow (szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0 , CW_USEDEFAULT, 0 , NULL , h1, hInstance, NULL );
动态菜单
下拉菜单,动态菜单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 HMENU h_1 = CreateMenu (); AppendMenu (h_1, 0 , 10087 , _T("新建(&N)\t Ctrl+N" ));AppendMenu (h_1, MF_SEPARATOR, 10080 , _T("-" )); AppendMenu (h_1, 0 , 10088 , _T("打开(&O)\t Ctrl+O" ));AppendMenu (hMenu, MF_POPUP, (UINT_PTR)h_1, _T("文件(&F)" ));HMENU h_2 = CreateMenu (); InsertMenu (h_2, 0 , MF_BYPOSITION, 10089 , _T("a" ));InsertMenu (h_2, 0 , MF_BYPOSITION, 10090 , _T("b" ));InsertMenu (h_2, 10089 , MF_BYCOMMAND, 10091 , _T("c" )); AppendMenu (hMenu, MF_POPUP, (UINT_PTR)h_2, _T("aaa" ));EnableMenuItem (h_1, 10087 , MF_GRAYED); EnableMenuItem (hMenu, 10087 , MF_ENABLED); EnableMenuItem (h_1, 0 , MF_DISABLED | MF_BYPOSITION); DeleteMenu (h_1, 0 , MF_BYPOSITION);
在createwindow下面加的话,要鼠标移上去才会刷新
1 2 3 4 5 6 7 8 9 10 ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); HMENU h_3 = CreateMenu (); InsertMenu (h_3, 0 , MF_BYPOSITION, 10189 , _T("1a" ));InsertMenu (h_3, 0 , MF_BYPOSITION, 10190 , _T("1b" ));InsertMenu (h_3, 10189 , MF_BYCOMMAND, 10191 , _T("1c" )); AppendMenu (hMenu, MF_POPUP, (UINT_PTR)h_3, _T("1aaa" ));SetMenu (hWnd, hMenu);
快捷菜单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 HMENU g_hRMenu; case WM_CREATE: g_hRMenu = LoadMenu (hInst, MAKEINTRESOURCE (IDR_MENU2)); break ; case WM_RBUTTONDOWN: { POINT pt; pt.x = LOWORD (lParam); pt.y = HIWORD (lParam); ClientToScreen (hWnd, &pt); HMENU tempMenu = GetSubMenu (g_hRMenu, 0 ); TrackPopupMenu (tempMenu, TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, 0 , hWnd, nullptr ); } break ;
GDI图形设备接口
实现了图形硬件和应用程序的分离
简化了开发人员的难度
GDI可以操作的图形对象 :
1、画点和画线
2、填充区域
3、文字
4、位图
在窗口绘制一个图形的步骤 :
1、得到设备环境句柄
2、修改设备属性
3、绘图
4、释放设备环境句柄
在windows里得到设备环境句柄的两种方法:
1、在WM_PAINT里去得到设备环境句柄
1 2 3 4 5 case WM_PAINT:hdc = BeginPaint (hWnd, &ps); EndPaint (hWnd, &ps);break ;
响应WM_PAINT有两个情况:1、窗口初创建 2、窗口出现无效区
窗口出现无效区的几种情况:1)窗口移动或大小改变
2)窗口隐藏后重新可见,或被其它窗口遮挡后重新可见
3)调用InvalidateRect或InvalidateRgn函数,使出现无效区
4)调用ScrollDC或者ScrollWindow函数,滚动客户区
2、在WM_PAINT消息外得到设备环境句柄
GetDC得到设备句柄, ReleaseDC释放设备环境句柄
1 2 3 4 5 case WM_LBUTTONDOWN: hdc = GetDC (hWnd); TextOut (hdc, 0 , 0 , _T("123" ), 3 ); ReleaseDC (hWnd, hdc); break ;
实例:绘图软件
1、画笔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int posX = 0 , posY = 0 ;bool isMove = false ;case WM_MOUSEMOVE: if (isMove) { int x = LOWORD (lParam); int y = HIWORD (lParam); hdc = GetDC (hWnd); MoveToEx (hdc, posX, posY, nullptr ); LineTo (hdc, x, y); ReleaseDC (hWnd, hdc); posX = x; posY = y; } break ; case WM_LBUTTONUP: isMove = false ; break ; case WM_LBUTTONDOWN: isMove = true ; posX = LOWORD (lParam); posY = HIWORD (lParam); break ;
GDI里面有一些预设的设备属性,预设了画笔,画刷,文字
如果要修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 case WM_LBUTTONDOWN:{ hdc = GetDC (hWnd); HPEN hpen = nullptr ; COLORREF c = RGB (255 , 0 , 0 ); hpen = CreatePen (PS_SOLID, 2 , c); SelectObject (hdc, hpen); MoveToEx (hdc, 0 , 0 , nullptr ); LineTo ( hdc, 100 , 100 ); DeleteObject (hpen); ReleaseDC (hWnd, hdc); } break ;
画圆弧
1 2 3 4 5 6 7 8 hdc = GetDC (hWnd); Arc (hdc, 100 , 100 ,400 , 400 , 0 , 0 , 250 , 400 ); ReleaseDC (hWnd, hdc);
画点
1 2 3 4 5 6 7 8 9 10 hdc = GetDC (hWnd); for (int i = 1 ; i <= 100 ; ++i) { SetPixel (hdc, i, 100 , RGB (255 , 0 , 0 )); } hdc = GetDC (hWnd); for (int i = 1 ; i <= 100 ; ++i) { SetPixel (hdc, i, 200 , GetPixel (hdc,i,100 )); }
画彩色的线
在同一时刻,GDI只允许同一属性的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 hdc = GetDC (hWnd); HPEN hp = CreatePen (PS_SOLID, 2 , RGB (255 , 0 , 0 )); SelectObject (hdc, hp);MoveToEx (hdc, 100 , 100 , nullptr );LineTo (hdc, 150 , 100 );DeleteObject (hp);hp = CreatePen (PS_SOLID, 2 , RGB (0 , 255 , 0 )); SelectObject (hdc, hp);MoveToEx (hdc, 150 , 100 , nullptr );LineTo (hdc, 200 , 100 );DeleteObject (hp);ReleaseDC (hWnd, hdc);
2、画刷
系统默认的画笔是黑色,画刷是白色。边框色是用画笔的颜色描边
1 2 3 4 5 6 7 8 9 10 11 hdc = GetDC (hWnd); Rectangle (hdc,100 ,100 ,200 ,200 ); ReleaseDC (hWnd, hdc);HBRUSH hr = CreateSolidBrush (RGB (255 , 0 , 0 )); HPEN hp = CreatePen (PS_SOLID,1 , RGB (255 , 0 , 0 )); SelectObject (hdc, hp);SelectObject (hdc, hr); Rectangle (hdc,100 ,100 ,200 ,200 ); DeleteObject (hr);DeleteObject (hp);
填充矩形区域, 也可以实现无边框
1 2 3 4 5 6 7 8 hdc = GetDC (hWnd); RECT r = { 100 , 100 , 400 , 400 }; HBRUSH hr = CreateSolidBrush (RGB (255 , 0 , 0 )); FillRect (hdc, &r, hr); ReleaseDC (hWnd, hdc);HBRUSH hr = CreateHatchBrush (HS_BDIAGONAL, RGB (255 , 0 , 0 ));