说明(期间写代码使用的VS2015,写博时用的VS2017,有些许差异,见谅)
1.字符问题
照着书上抄代码都发现了问题,书上使用的是VC++,本人使用的VS2015,存在着一些字符格式问题。
VS2015默认的是Unicode字符集,VC使用多字符字符集,当然你也可以去VS里面改设置,这是后话,暂且不表。
在其中,遇到了(wchar_t)类型的数据,都知道,char占一个字节,而wchar_t占两个字节,就是char的扩展类型,它自己也有一套函数集,比如求wchar_t数组长度的函数为wcslen,虽有变化,大致相同,熟悉就好了。
2.Win32 Application 和 Win32 Console Application 之间的区别
(不记得是哪里抄的一段话了。。。。)
1、程序不同
Win32 Application 是标准windows程序,完全拥有windows的特性,可以通过鼠标点击窗口来完成控制。(入口函数–WinMain)
Win32 Console Application是控制台应用程序,类似于MS-DOS窗口,只能运行命令行程序,不具备消息响应机制。(入口函数–main)
2、入口函数不同
Win32 Application 入口函数是WinMain(),它具有消息响应机制,可以运行图形化的C++程序。
Win32 Console Application入口函数是main(),可以访问部分windows API函数,如果你编写传统的C程序,必须建立Win32 Console程序。
3、Win32 Application它通过GUI(Graphics User Interface图形用户接口)可以把窗口界面做得比较个性化,比如圆形的、不规则形状的等等,另外,我们还可以通过鼠标点击来完成控制。所以说它是基于WINDOWS平台的32位开发环境开发应用程序(即,SDK程序)。入口函数为WinMain()。Win32 Console Application(win32控制台应用程序)往往是像MS-DOS窗口(XP中叫命令提示符)的样子出现,我们得用键盘输入各种命令来使用它,它与纯dos程序区别是:它是32位的;或者叫CUI(Character User Interface字符用户接口)。console程序以main()为入口,可以访问部分windows API函数,比如创建窗口、对话框等等。
3.第一个Windows程序–WinMain
VS(文件 -> 新建 -> 项目 -> windows桌面 -> Windows桌面应用程序 )反正就是创建一个win32项目的空项目(没有初始代码的那种,VS版本不同显示的新建项也不同,不过总而言之,建一个空白Windows桌面应用程序(Win32 Application)就可以了)建不了空白的也无妨,把文件删一下就可以。
首先新建一个cpp文件,用于编写代码(因为建的是一个空项目),如下图所示:
然后开始编写代码: 可以划分为以下七步—>>>
1.编写Win Main函数 —————- 类似于编写main函数,都是入口函数
2.设计窗口类,WNDCLASS ———— 有过封装,直接使用,设置参数
3.注册窗口类 ———– 需要先注册
4.创建窗口 ————– 创建
5.显示并更新窗口 ——– 显示
6.编写消息循环 ———– 循环查询消息队列,处理消息,针对不同的消息做出不同响应(由此实现一个应用程序)
7.编写窗口过程函数 —— 怎么响应消息(对消息做出对应的处理)
其中使用的各个函数在代码中有相应注释:
_T(),主要就是解决字符编码问题,真麻烦,感觉 (可以去链接看一下)
MSG可以直接理解为一个消息结构体,存储着不同的消息。
最后可以发现,程序关闭时的消息传递是:WM_CLOSE -> WM_DESTROY -> WM_QUIT,后面还会遇到,暂且不表。
1 #include <windows.h> 2 #include <stdio.h> 3 4 #include <tchar.h> 5 6 /* 7 窗口过程函数的声明 WinSunProc 8 */ 9 LRESULT CALLBACK WinSunProc( 10 HWND hwnd, // 窗口句柄 11 UINT uMsg, // 消息标识符 12 WPARAM wParam, // unsigned int 13 LPARAM lParam // long 两个附加信息 14 ); 15 16 17 /* 18 WinMain(),入口函数 19 HINSTANCE hInstance;程序当前运行的实例的句柄 20 HINSTANCE hPrevInstance;当前实例的前一个实例的句柄,win32环境hPrevInstance = null,参数无用 21 LPSTR lpCmdLine;传递应用程序的命令行参数,以空终止的字符串 22 int nCmdShow;窗口显示效果,最大/最小/隐藏 23 */ 24 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 25 { 26 /* 27 设计窗口类 28 */ 29 WNDCLASS wndcls; // 定义一个窗口类 30 // 设置该窗口的各个参数 31 wndcls.cbClsExtra = 0; 32 wndcls.cbWndExtra = 0; 33 wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 34 wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); 35 wndcls.hIcon = LoadIcon(NULL, IDI_ERROR); 36 wndcls.hInstance = hInstance; 37 wndcls.lpfnWndProc = WinSunProc; // 窗口过程函数 38 wndcls.lpszClassName = _T("sunxin2006"); // 窗口类名 39 wndcls.lpszMenuName = NULL; // 菜单 40 wndcls.style = CS_HREDRAW | CS_VREDRAW; 41 42 /* 43 注册窗口类 44 */ 45 RegisterClass(&wndcls); // 注册窗口类 46 47 /* 48 创建窗口类 49 */ 50 HWND hwnd; // 窗口句柄 51 // 创建窗口 52 hwnd = CreateWindow(_T("sunxin2006"), _T("Windows程序"), WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL); 53 54 /* 55 显示与更新窗口 56 */ 57 ShowWindow(hwnd, SW_SHOWNORMAL); // 激活并显示,窗口正常大小,(第一次显示 58 // 目前,整个客户区无效, UpdateWindow 会检查窗口的 Update Region无效区域,当其不为空时才发送 WM_PAINT 消息 59 // 所谓无效区域就是需要应用程序重新绘制的区域,反之则为有效区域 => 有无效区域时,发送WM_PAINT消息 60 UpdateWindow(hwnd); // 会发送一个WM_PAINT信息 61 62 MSG msg; // 消息结构体 63 // 消息循环代码 64 while (GetMessage(&msg, NULL, 0, 0)) // GetMessage函数接收WM_QUIT返回0,此外非0,出错-1 65 { 66 // GetMessage函数 要检索其消息的窗口的句柄。该窗口必须属于当前线程。 67 // 如果 hWnd 为 NULL,则 GetMessage 将检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd 值为 NULL 的任何消息。 68 // 因此,如果 hWnd 为 NULL,则同时处理窗口消息和线程消息。 69 // 如果 hWnd 为 - 1,则 GetMessage 仅检索当前线程的消息队列中hwnd值为 NULL 的消息 70 TranslateMessage(&msg); // 把快捷键消息转换为字符消息,并将转换后的新消息投递到调用线程的消息队列中 71 DispatchMessage(&msg); 72 // DispatchMessage函数分发一个消息给窗口程序,通常消息从GetMessage函数获得或者TranslateMessage函数传递的 73 // 消息被分发到回调函数(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息。 74 75 // 函数DispatchMessage()负责将消息派送到相应的窗口函数。它根据msg结构中的hWnd窗口句柄成员找到相应的窗口类, 76 // 然后根据注册窗口时wndcls类结构找到相应的窗口函数WinSunProc。由消息传递函数将消息传递给窗口函数WinSunProc进行消息处理。 77 } 78 return msg.wParam; 79 } 80 81 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 82 { 83 switch (uMsg) 84 { 85 case WM_CHAR: //字符信息 char * -> WCHAR * 86 // char szChar[20]; 87 // sprintf(szChar, "char code is %d", wParam); 88 // MessageBox(hwnd, _T(szChar), _T("char"), 0); 89 wchar_t szChar[20]; 90 swprintf(szChar, 100, L"char code is %d", wParam); 91 MessageBox(hwnd, szChar, _T("char"), 0); 92 break; 93 case WM_LBUTTONDOWN: // 鼠标左键信息 94 MessageBox(hwnd, _T("mouse clicked"), _T("message"), 0); 95 HDC hdc; // 为 DVTARGETDEVICE 结构中指定的设备创建设备上下文, TextOut等函数所需参数 96 hdc = GetDC(hwnd); //不能在响应MWM_PAINT时调用 97 TextOut(hdc, 0, 50, _T("中文有什么问题吗?"), wcslen(_T("中文有什么问题吗?"))); // 位置坐标(0,50) 98 // 中文乱码问题,wchar 与 char 所占空间不同,故而计算空间需要使用wcslen函数, 99 ReleaseDC(hwnd,hdc); // GteDC 配套函数,释放资源 100 break; 101 case WM_PAINT: // 系统会在多个不同的时机发送 WM_PAINT 消息:当第一次创建窗口,改变窗口大小,把窗口移出,最大化,最小化时 102 HDC hDC; 103 PAINTSTRUCT ps; // 绘图信息结构 104 hDC = BeginPaint(hwnd, &ps); // BeginPaint只能在响应MWM_PAINT时调用 105 // BeginPaint 的一个作用就是把该 Update Region(即无效区域) 置为空, => 全部为有效区域 106 // 这样如果不调用 BeginPaint,窗口的Update Region 就一直不为空,系统就会一直发送 WM_PAINT 消息。 107 TextOut(hDC, 100, 0, _T("http://www.qutuku.com"), strlen("http://www.qutuku.com")); 108 EndPaint(hwnd, &ps); // 释放 hDC 109 break; 110 case WM_CLOSE: 111 if (IDYES == MessageBox(hwnd, _T("是否真的结束?"), _T("message"), MB_YESNO)) 112 { 113 DestroyWindow(hwnd); 114 } 115 break; 116 case WM_DESTROY: // DestroyWindow销毁后会发送一个WM_DESTROY消息, 117 PostQuitMessage(0); // PostQuitMessage向应用程序的消息队列中投递一条 WM_QUIT 消息,并返回 118 break; // GetMessage(&msg, NULL, 0, 0)收到 WM_QUIT 消息,循环结束 119 default: 120 return DefWindowProc(hwnd, uMsg, wParam, lParam); 121 // DefWindowProc这个函数是默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理 122 } 123 return 0; 124 }
主要还是熟悉整个运行流程,搞清楚有哪几步,每一步都是做一些什么样的工作,即可。
2022-07-31(07-13的工作,拖延症晚期。。)
原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/278155.html