如果你手里有一个现成的EXE, 以及EXE相关联PDB文件, 还有相关联的CPP文件和H文件. 你如何用VS调试? (当然你可以选择WinDbg.不过这里就讨论VS)

你或许想问我干嘛不从一开始就用VS写代码?

设想, 有一个人喜欢用 NMAKE 和 MAKEFILE 创建工程. 他已经编译链接好了. 得到了 EXE. PDB. 现在他叫你帮他调试一下. 你又喜欢用VS调试, 怎么办? 对. 这就是下面要说的.

首先推荐阅读这个链接作为热身:

https://msdn.microsoft.com/zh-cn/library/0bxe8ytt.aspx

总的来说, 有2种办法

1. 附加到进程

2. 创建调试EXE的解决方案

无论你选择哪种, 步骤是类似的:

首先的首先, 准备工作: 确保PDB文件和CPP文件以及H文件的相对路径不发生变化.

因为PDB中保存了CPP文件和H文件的相对路径, 这样调试器才知道去哪里找源文件和头文件. 如果你挪动PDB或者CPP文件或者H文件导致它们之间的相对路径变了的话, 调试器就找不到符号了. 你就没法打断点. 后续的调试工作也就无法进行.

1.打开VS

2.把源文件组织为一个项目:文件->新建->从现有代码创建项目->选择项目文件位置, 比如VS_DEBUG\ClientSrc, 项目名称比如说ClientSrc, 将文件从这些文件夹添加到项目中, 选择比如说C:\TestProject, 确保所有你写的CPP和H文件都在这个目录(这些源代码文件只是会被引入项目, 但不会拷贝到VS_DEBUG\ClientSrc目录下, 也就意味着你仍然可以随时修改代码并用NMAKE构建而不必担心代码在VS中更新的问题)

##########################################################

# 注意这一步非常重要, 如果你只是单纯地用VS打开某个源文件而不是把所有的源文件组织到一个解决方案里的话,

# 你是无法使用"转到定义", "转到声明", "查看定义", "查找所有引用"这些功能的, 你查看代码的时候会很麻烦.

##

设置源文件搜索路径:

然后右击解决方案->属性->通用属性->调试源文件->设置为C:\TestProject, 这样调试器知道在这个目录可以搜索到你的源文件.

3.文件->打开->项目/解决方案->在右下角选择"可执行项目文件(.exe)"->选中"添入解决方案"->打开你想调试的EXE文件即可, 比如 Client.exe

4.现在你可以看见解决方案中有2个项目, 一个是只有代码的项目名为ClientSrc. 一个是只有EXE的项目名为Client.

5.把Client设为启动项目

6.设置PDB的位置: 选中Client项目, 在工具栏点击:调试->选项和设置->符号->把PDB文件的路径添加进去并打勾即可

7.设置命令行参数, 工作目录:选中Client项目, 右击, 点属性, 就可以看到设置命令行参数和工作目录的地方

8.在ClientSrc中打上断点, 调试Client即可. 或者你用附加到进程也行.

附上几张截图:

参考资料:

https://msdn.microsoft.com/zh-cn/library/ms241613.aspx

https://msdn.microsoft.com/zh-cn/library/0bxe8ytt.aspx

后记:

我写这篇BLOG的原因是学习Inside COM 第10章代码的时候遇到的问题.

作者用的MAKEFILE来完成了 IDL的编译, 组件的编译, DLL的生成(Server.dll), EXE的生成(Server.exe, Client.exe).

Server.dll会被加载到Client.exe的进程中从而Client.exe可以使用Server.dll中的组件.

Client.exe也可以与Server.exe使用COM的LPC(Local Procedure Call, 即单机版的Remote Procedure Call, RPC)来完成进程间通信, 从而Client.exe也可以使用Server.exe中实现的组件.

如果要把作者的代码在VS中建立一个DLL工程生成Server.dll, 两个EXE工程分别生成(Server.exe)与Client.exe也不是不行. 只不过没有MAKEFILE来得那么顺畅. (因为IDL文件的编译会生成几个.c文件和.h文件, 而且这些文件要用到后面DLL与EXE的生成, 但目前看来, 我不知道怎么让VS的解决方案中也能把这个过程也自动化起来.只能依靠MAKEFILE要方便一些.一个nmake命令就够了.)

当然我可以用WinDbg来调试这个项目. 但是我想尝试一下是否用VS也能完成. 因为以前没试过. 摸索了一段时间想了个这个办法出来.

这里要补充2个比较重要的问题.

1.

调试Server.dll中的代码, 打上断点提示"当前不会命中断点, 没有为该文档加载任何符号"

这是因为Client.exe在没有加载Server.dll之前. Server.dll对应的Server.pdb也没加载.当Server.dll加载之后就好了.可以通过如下步骤验证.

1.1

在Client.cpp的main函数打上断点.

在CMPNT1.CPP中任意一个地方,比如CA::FxStringIn,打上断点(提示"当前不会命中断点...")

1.2

按F5调试, 点击工具栏的调试->窗口->模块(这个窗口只有在调试已经启动的情况下能勾选, 没按F5启动调试是无法打开这个窗口的)

你可以看到Client.exe已经加载, 但是找不到Server.dll, 此时CMPNT1.CPP中的断点仍然提示"当前不会命中..."

单步执行main函数(并用命令告诉Client.exe加载Server.dll而不是去找Server.exe), 执行了CoCreateInstance之后, 再去查看模块窗口, 发现Server.dll已经加载, 此时CMPNT1.CPP中的断点变为可以命中的断点了

2.

按照上面所述的步骤1.1, 1.2做了, 看到Server.dll也加载了. 但是CMPNT1.CPP中的断点仍然提示"当前不会命中..."

2.1

原因是pdb与dll不匹配.

2.2

这是因为此时的Server.pdb对应的是Server.exe而不是Server.dll. 把MAKEFILE中"nmake -f make-one OUTPROC=1"这一行注释掉即可.

MAKEFILE大概是按如下顺序生成项目的.

编译IDL, 生成几个.C文件和.H文件.

编译所有的.C和.CPP等等文件

链接生成Client.exe, 生成Client.pdb

链接生成Server.dll, 生成Server.pdb

链接生成Server.exe, 生成Server.pdb(把Server.dll对应的pdb给覆盖了)

所以不生成Server.exe即可.

3.

调试Server.exe中的代码, 打上断点提示"当前不会命中断点, 没有为该文档加载任何符号"

Server.exe是一个独立的进程, 不会加载到Client.exe的进程空间中. 所以调试Client.exe的时候不会命中Server.exe的代码断点.

首先, 把MAKEFILE的"nmake -f make-one"注释掉, 不生成Server.dll, 只生成Server.exe.

3.1 不可行的办法

把Server.exe也添加到解决方案中调试.(就跟添加Client.exe的方法一样)

这种办法是不行的. 因为一个调试器同一时刻只能调试一个进程.

选中解决方案资源管理器中的Server, 按Delete键移除.

3.2 第一种可行的办法

调试Client.exe 在 Client.cpp的 main函数打上断点. 单步调试. 执行到CoCreateInstance的时候

打开任务管理器, 你会发现启动了一个Server.exe

点击VS的工具栏:调试->附加到进程->选Server.exe->按F5继续执行->

你会发现CMPNT1.CPP中Server.exe的代码断点命中了.->再按F5继续执行就会跳转到Client.exe的下一个断点(如果有的话, 没有就运行到程序结束)

用这种方法, 只要2个进程中的任意一个后续代码还有断点, 调试器就会切换到相应的进程命中断点. 当2个进程后续的代码都没有断点的话, 你按F5就会让2个进程都一直运行到结束. 如果你希望用F10单步, 确保不漏掉每个进程中的所有代码的话, 进程间跳转/通信的时候又会有很多没有源码的代码.(当然你可以边调试边给后面的代码打断点, 直接按F5跳过进程切换的代码.) . 总的来说有方便的地方也有不方便的地方(你需要在调试开始的时候选择附加的进程. 以及随时去添加断点以便用F5跳过进程切换的代码.).

举个例子:

现在你在 Client.cpp 只给 main打了一个断点, 在 CMPNT1.CPP 中 有2个断点, 一个在 CA::FxStringIn上 还有一个在 CA::FxStringOut 上

按F5开始调试, 命中 main函数, F10单步, 调用CoCreateInstance之后, Server.exe启动, 选择附加到进程Server.exe, 然后按F5, 命中Server.exe的CA::FxStringIn, F10单步, CA::FxStringIn快执行完了之后进入rpcrt4.dll的进程通信代码(无源码), 此时不能按F5, 按F5之前先去Client.cpp的CA::FxStringIn后面一行代码打上断点, 然后按F5, 命中Client.cpp中刚刚打的断点, 继续F10, 命中Server.exe中的CA::FxStringOut, 继续F10, 这回我们学聪明点, CA::FxStringOut返回之前我们就去Client.cpp中调用FxStringOut的代码后一行打上断点, 直接F5就跳过了rpcrt4.dll的进程通信代码, ... 反复如此调试即可

可以看出, 虽然能用. 但是多少还是有点麻烦.

3.3 第二种可行的办法

就像我们创建一个解决方案调试Client.exe一样.再创建一个解决方案调试Server.exe就行啦. 2个调试器分别调试2个EXE, 互不干扰.

这个用起来最方便. 只不过你要创建2个解决方案同时调试2个EXE. 也是它麻烦的地方.

总之,发生了上面所说的问题.建议去工具栏的调试->选项和设置->符号 看看PDB的搜索位置是否设置对了. 以及是否正确配置了"对以下模块自动加载符号"(这里面可以配置那些DLL或EXE自动加载符号, 哪些不自动加载.)

项目下载:

http://pan.baidu.com/s/1A0FPs

目录:

CHAP10

  SRC // MAKEFILE以及源文件, nmake 生成, nmake clean清理

  VS_DEBUG // 用于调试DLL和EXE的VS2013解决方案, 点击.sln文件即可打开解决方案, 打开之前确保已经用MAKEFILE生成了EXE和DLL

建议:

MAKEFILE中"nmake -f make-one"和"nmake -f make-one OUTPROC=1"只保留一个. 避免Server.exe的PDB把Server.dll的PDB给覆盖了.

Demo.sln, Debug目录, 以及其他的几个就是调试Client.exe建立的VS2013的解决方案.如果下载下来因为路径问题用不了的话, 可以按照上面说的步骤重新建立即可.

使用方法:

管理员权限打开"VS2013 开发人员命令提示", 切换到MAKEFILE的目录.

nmake构建项目.

nmake clean清理项目.

参考资料:

http://www.cnblogs.com/MigCoder/p/3368319.html

http://www.cnblogs.com/lidabo/p/3486134.html

https://technet.microsoft.com/zh-cn/magazine/ms241613.aspx#bkmk_find_symbol___pdb__files

如何用VS调试不属于解决方案的EXE和DLL程序的更多相关文章

  1. Safari 前端开发调试 iOS 完美解决方案

    转http://www.2cto.com/kf/201403/283404.html afari 前端开发调试 iOS 完美解决方案 2014-03-05      0个评论    来源:Safari ...

  2. vscode在执行 npm任务的时候,会先执行package的name@version 然后命令名 加 当前路径,问题是我的引入路径e是小写的,会导致调试错误,解决方案:没找到,先手书吧

    vscode在执行 npm任务的时候,会先执行package的name@version 然后命令名 加 当前路径,问题是我的引入路径e是小写的,会导致调试错误,解决方案:没找到 Executing t ...

  3. 如何用Visual Studio 2013 (vs2013)编写C语言程序

    如何用Visual Studio 2013 (vs2013)编写C语言程序 (2014-05-16 10:58:15)   Visual Studio 2013是一个很强大的软件,但是刚开始用Visu ...

  4. 如何用Baas快速在腾讯云上开发小程序-系列4:实现客户侧商品列表、商品详情页程序

    版权声明:本文由贺嘉 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/431172001487671163 来源:腾云阁 h ...

  5. 调试技巧 —— 如何利用windbg + dump + map分析程序异常

    调试技巧 —— 如何利用windbg + dump + map分析程序异常 逗比汪星人2011-09-04上传   调试技巧 —— 如何利用windbg + dump + map分析程序异常 http ...

  6. vs2013中$(TargetPath)与Link.OutputFile不同,导致调试debug找不到exe

    之前把VS2008项目升级为VS2013项目后,出现了VS2013调试debug找不到exe文件的现象,如:http://blog.sina.com.cn/s/blog_6c617ee301013xt ...

  7. 转:使用IDA动态调试WanaCrypt0r中的tasksche.exe

    逆向分析——使用IDA动态调试WanaCrypt0r中的tasksche.exe 转:http://www.4hou.com/technology/4832.html 2017年5月19日发布 导语: ...

  8. C# 最基本的涉及模式(单例模式) C#种死锁:事务(进程 ID 112)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务,解决方案: C#关闭应用程序时如何关闭子线程 C#中 ThreadStart和ParameterizedThreadStart区别

    C# 最基本的涉及模式(单例模式) //密封,保证不能继承 public sealed class Xiaohouye    { //私有的构造函数,保证外部不能实例化        private  ...

  9. 通过Windows Visual Studio远程调试WSL2中的.NET Core Linux应用程序

    最近两天在Linux中调试.NET Core应用程序,同时我发现在Linux中调试.NET Core应用程序并不容易.一直习惯在Visual Studio中进行编码和调试.现在我想的是可以简单快速的测 ...

随机推荐

  1. FZU 2032 高精度小数加法

    题目描写很没意思..就是说给出n个小数 求它们的总和 因为给出的小数点后最多16位而要求保存至12位 而能直接使用的最精确的double只能到12位 于是13的进位可能被忽略 于是不可以用double ...

  2. 2016.05.04,英语,《Vocabulary Builder》Unit 22

    acerb/acri: comes from the Latin adjective acer, meaning 'sharp' or 'sour'. acerbic: [ə'sɜːrbɪk] adj ...

  3. Ruby--Array

    --后面连接其它数组:[ARRAY].concat([OTHER ARRAY]) --排序:sort,进阶:sort_by{|obj| obj.[VALUE]} --随机获取:[ARRAY].samp ...

  4. MZhong's Resume

    MATTHEW.ZHONG Male,27 Age Front-End Developer matthew.zhong@morningstar.com OBJECTIVE My objective i ...

  5. 时间函数 date strtotime

    date_default_timezone_set('Asia/Shanghai');echo strtotime('Today');echo strtotime(date('Y-m-d')); 获取 ...

  6. Nobel Lecture, December 12, 1929 Thermionic phenomena and the laws which govern them

    http://www.nobelprize.org/nobel_prizes/physics/laureates/1928/richardson-lecture.pdf OWEN W. RICHARD ...

  7. mysqli_query($link,'SET group_concat_max_len=8192');

    mysqli_query($link,'SET group_concat_max_len=8192'); $sql = 'SELECT GROUP_CONCAT(w) FROM ---'; mysql ...

  8. Networking with PHP

    PHP Advanced and Object-Oriented Programming 3rd Edition

  9. 关于C和C++动态链接库的几个问题

    问题: 1.写一段C++程序,编译成动态链接库后,C程序怎么访问? 2.写一段C程序,编译成动态链接库后,C++程序怎么访问? 3.写一个类,编译成动态链接库后,里面的public变量能否访问? 对于 ...

  10. day08

      软件系统体系结构   常见软件系统体系结构B/S.C/S 1.1 C/S C/S结构即客户端/服务器(Client/Server),例如QQ: 需要编写服务器端程序,以及客户端程序,例如我们安装的 ...