【答疑释惑第三十六讲】Windows下如何调试?

疑惑一

Windows窗口程序到底能不能用printf?

很多小伙伴在控制台下写程序时,要打印或者调试很方便,用printf就可以直接打印输出,方便看结果,但是在编写窗口程序时,由于窗口程序的子系统是Windows,而不是控制台的子系统console,因此非字符模式是不能用printf来输出的,那么到底在窗口模式下能不能用printf呢?

答案是肯定的,但是需要我们自己创建一个控制台终端,可以用Windows提供的API函数AllocConsole来创建一个控制台,以后的输出都是在这个控制台里操作。当然只创建了控制台还不行,还得重定向输入、输出和错误输出口,重定向有几种方式:

最简单的就是用freopen函数绑定新的标准输入输出,方法如下: AllocConsole(); freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr);

如果只是想把printf的结束输入文件,可以直接把文件句柄赋给标准输入: FILE * fpin = fopen ("c://in.txt" ,"r" ); *stdin = *fpin;

最后一种就比较麻烦,就不多说了,下面的函数实现重定向: void RedirectConsole(void) { DWORD hdl = (DWORD)GetStdHandle(STD_OUTPUT_HANDLE); int hConHandle = _open_osfhandle(hdl, _O_TEXT); _iobuf *fp = _tfdopen(hConHandle, TEXT("w")); *stdout = *fp; setvbuf(stdout, NULL, _IONBF, 0);

输入关键printf获取相关资料,不懂得可以后台继续问。

疑惑二

Windows窗口不用控制台能不能打印调试信息

在窗口程序模式下,要在终端打印只有按上面的方法进行输出,其实只是调试看打印,可以用Windows提供的API函数实现信息打印功能,只要在debug窗口下都可以看到,而不需要像上面那样分配一个控制台窗口。这个API就是OutputDebugString,该函数的参数是一个字符串,他能把一个字符串输出到调试窗口中,可能用的伙伴就说了,只能输入文本串多没意思,要是能想printf那样输出任意类型的格式多好。其实只要我们简单改装一下就能到达跟printf函数一样的结果,下面就是一个改装好的函数参考:

void OutputDbgInfo(const TCHAR *format, ...) { TCHAR szData[512] = {0}; va_list arg; va_start(arg, format); _vsntprintf(szData, sizeof(szData)-1, format, arg); va_end(arg); OutputDebugString(szData); }

大家从函数参数上也能看出来,实际上跟printf参数一样,能实现可变参数的任意格式了。

至于查看窗口,VS就自带debug窗口,有人说要是编译好后脱离了VS环境怎么办?刚才说了,只要是debug窗口就可以,有不是只有VS才带有debug窗口,比如有Dbgview这个小程序(网上可以下载)就可以接收并显示调试信息,你可以启动它来查看。

疑惑三

WM_CLOSE,WM_DESTROY,WM_QUIT有什么区别

WM_CLOSE消息:

该消息是在关闭应用程序窗口时触发,典型的就是当你点击应用程序右上角的叉号时就会走到该消息处,该消息是关闭应用程序时最先接收到,因此这时可以阻止窗口关闭和退出应用程序,还可以用于提示保存、自动保存等操作。如果要退出应用程序,一般会调用DestroyWindow这个函数,Windows默认处理就是直接调用这个函数,该函数在关闭窗口后发送WM_DESTROY消息给应用程序。

WM_DESTROY消息:

该消息接收到时已经将窗口从屏幕上关闭了,视觉上已经看不到窗口,虽然这个时候还能阻止应用程序彻底退出,但是对于一个窗口应用程序在主窗口都已经关闭的情况下再不退出,已经没有实际意义了。一般这个时候主要是卸载一些全局句柄、释放内存和对象等操作。该消息最后一般会调用PostQuitMessage这个函数,该函数简单的投递WM_QUIT消息对消息队列中。

WM_QUIT消息:

GetMessage在获取其他任何消息,返回值都不是0,唯独这个消息,获取该消息后返回0,于是退出消息循环,最终WinMain主线程函数退出,结束程序运行。


原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2016-01-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后台全栈之路

基于汇编的 C/C++ 协程 - 实现

将 libco 和 libevent 两者的功能糅合起来,所以我把我的工程,命名为 libcoevent,意为 “基于 libevent 的同步协程服务器编程框...

5793
来自专栏Java帮帮-微信公众号-技术文章全总结

Python常见面试题【悟空教程】

1.MySQL 数据库总结 MySQL 可以建多少个数据库,理论上是没有限制的,每一个数据库可以有上亿的对象,但是一般基于硬件要求、效率问题一般不超过64个, ...

1832
来自专栏C/C++基础

Linux命令(9)——tcpdump命令

tcpdump是一款类Unix/Linux环境下的抓包工具,允许用户截获和显示发送或收到的网络数据包。tcpdump 是一个在BSD许可证下发布的自由软件。

1403
来自专栏SDNLAB

POF技术分享(二):POF交换机源码结构

一:函数调用关系图 POF交换机先会进行基本配置的初始化、交换机资源初始化等,然后开启交换机与控制器通信进程,建立连接进行通信,最后开启基于流表的数据包匹配与处...

3797
来自专栏张戈的专栏

Linux运维工程师:30道面试题整理

前段时间,我在准备面试的时搜到的一套 Linux 运维工程师面试题,感觉比较全面,一直保存在草稿,刚在整理后台时翻了出来,干脆就发出来好了,以备不时之需。 1....

2K5
来自专栏IT笔记

JAVA中CAS原理详解

在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: 在多线程竞争下,加锁、释放锁会导致比较多的上下文切...

6058
来自专栏NetCore

保护连接字符串

保护连接字符串 摘自MSDN 保护对数据源的访问是安全应用程序最重要的目标之一。为了帮助限制对数据源的访问,必须保护连接信息(例如用户标识、密码和数据源名称)的...

2075
来自专栏智能算法

Python学习(九)---- python中的线程

原文地址: https://blog.csdn.net/fgf00/article/details/52773459 编辑:智能算法,欢迎关注! 上期我们一起学...

1642
来自专栏Java架构

前沪江高级架构师学习笔记分享:分布式框架设计与实现

2046
来自专栏求索之路

Android数据层架构的实现 上篇

最近我们app的服务器吃不消了,所以我在为服务器增加缓存层之后,又想到在app端进行二级缓存以减少app对服务器的访问。我想很多app应该在项目的初期架构的时...

3198

扫码关注云+社区

领取腾讯云代金券