[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]
1、启动VS2017开发环境和VS2017帮助文档工具。在新打开的VS2017软件中,新建一个“Windows控制台应用程序”,同时,将项目名称修改为“MainWindow”。注意,这里如果创建“Windows桌面应用程序”,VS2017会自动添加创建一个完整主窗口的所有代码,最后需要手动删除才能进行我们今天的代码实验,太麻烦了;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/b442d6d246fe474e3390b50bb0ef354f51b81fa8.jpg)
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/f59dbe39131fceecd6cdefc179c4ec9958430ba8.jpg)
4、在弹出的“MainWindow属性页窗口”中,将配置设置为“所有配置”(保证修改所有配置,包括Debug和Release),然后在左侧列表中选择“链接器 > 系统”,接着在右侧属性列表中,选择子系统为“窗口(/SUBSYSTEM:WINDOWS)”。修改完毕后,点击确定按钮关闭属性设置;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/edafb3bcbe2f4770510c596e6f3b3b86032179a8.jpg)
5、再次点击VS2017工具栏上的“本地Windows调试器”按钮编译运行程序。VS2017会弹出错误窗口,同时在输出面板中给出错误提示信息,说“找不到入口函数WinMain”。希望你此刻能想起“Using Window Classes”主题中的示例代码,它用的就是WinMain函数。即Windows桌面程序的入口函数是WinMain,而不是C语言的main,这是微软规定的,因此,如果我们希望使用VS2017开发Windows桌面程序,那么就得遵守他制定的规则(如果你排斥WinMain,想使用自定义的入口函数,咋整?);
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/04201aa355e983aecfc3df9e68efe078153169a8.jpg)
6、为了尽快实现目标,我们可以偷懒,直接拷贝MSDN中“Using Window Classes”主题内给出的代码。然后覆盖掉main.cpp文件中的main()函数。替换代码之后,点击VS2017菜单栏上的“生成 > 生成解决方案”(或F7),尝试编译解决方案中的所有项目;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/988e1c532f632385d3226425cce833e038725da8.jpg)
7、编译之后,VS2017直接在输出面板中给出了一堆错误信息。虾米???MSDN上的示例代码竟然有错误,难道是我拷贝的方式不对?开玩笑,当然不是了。既然出错了,那么我们就开始改错。双击输出面板中的第一条错误提示,VS2017会自动帮我们定位到出错的代码位置;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/baab208630486143eac0ce858febf6a75e0f53a8.jpg)
9、修改完第一个错误后,再次编译解决方案,确认一下修改是否正确。查看输出面板中的错误列表,可以确认之前的错误提示消失了。由此可以确定,第一条编译错误已经被正确改正了。接下来,按照同样的方法,修改InitInstance的函数声明;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/506d92f1d8a7263302904b57c02c56ee7a7f44a8.jpg)
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/ab966c6b0ce265e76d1be2cc9f23beb9773eb7a8.jpg)
10、修改完InitInstance的函数声明后,再次编译解决方案。发现输出窗口中的第一条错误是“无法从HGDI晦倘佳鳎OBJ转换为HBRUSH”,这是一条类型转换错误。双击错误提示后,跳转到代码中的出错位置。直接将GetStockObject()返回值强转为HBRUSH(MSDN中查一下GetStockObject()函数就知道为什么可以这么做了);
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/d04eec260d9a310e7b8d6f9e31b842406bfea2a8.jpg)
11、修改完毕后,再次编译解决方案。溽朽孑臾查看VS2017输出面板中的第一条错误提示。它说“无法从const char[9]转换为LPCWSTR”。这实际上是一个多字节字符集和Unicode字符集的问题。因为MSDN中的示例代码是基于早期的多字节字符集编写的,但是我们的这个项目确实默认采用了Unicode字符集(不懂的话,记得查查这两种字符集的知识)。解决这个问题很简单,直接用tchar.h中定义的字符串自适应宏“_T()”将字符串包起来即可。这个宏会根据当前项目采用的字符集,自动将括起来的字符串替换为普通的多字节字符串或者Unicode字符串(由L 和“”构成,例如:L "Hello")。可以在项目属性中的“常规 ”类别中指定项目采用的字符集;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/91091efc77f7980e2034c5c5d4db3620b83a91a8.jpg)
12、修改完毕后,再次编译解决方案。然后查看输出面板中的错误列表。第一条错误信息又是一个类型错误,“无法从HANDLE转换为HICON”。双击错误提示,跳转到出错代码。直接在Loa颊俄岿髭dImage前加上“(HICON)”,将其返回值强制转换为需要的HICON类型(为啥要这样?MSDN查LoadImage函数);
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/8974c38a59de45070315bec45e413a8ca70885a8.jpg)
13、再次编译解决方案,此时输出的错误变为“CreateWindow函数中的第2个参数无法从const char [11]转换为LPCWSTR”。又是一个字符集问题,直接跳转到出错位置,将字符串加_T();
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/c6b994775ddd884c7d5ea9936cef28066a01f6a8.jpg)
14、再次编译解决方案。这次更绝!出现“无法解析的外部符号”错误。说人话就是它只找到了函数声明,找不到函数定义。这种错误,双击错误提示就无法定位到具体的代码了。只好向上翻,发现MainWndProc函数确实只有声明,没有定义。MSDN上的示例代码,呵呵!
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/aebdff86242fa872330b3850bfdaf05e4b23e9a8.jpg)
15、在代码的最后面,补上MainWndProc函数的定义。这个函数中直接调用默认的窗口过程处理函数DefWindowProc()。然后再次编译解决方案,终于编译成功了;
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/7496877bbbf4da58cbce58fdea0f8b56ac04d7a8.jpg)
![[Win窗口编程(2)] 尝试创建一个主窗口[TZZ]](https://exp-picture.cdn.bcebos.com/116b1ae23ea23a426e6e26a43733ec3835bbc0a8.jpg)