欢迎来到百丽百科
百丽百科
当前位置:百丽百科 > 网络

vs2010 调试dll源代码_vs2010调试-尝试调试dll源码。

日期:2023-09-27 05:40

第一步:

打开“调试”——“选项和设置”——点击调试下“常规”——设置启用“启用.NET Framework源代码单步执行 ”

第二步

选择“符号”——选择Microsoft符号服务器——设置符号缓存目录

?

这是初步的尝试,还没有实验成功。

微软文档:https://m.zs-baili.com/zh-cn/visualstudio/debugger/how-to-debug-dotnet-framework-source?view=vs-2017

标题:如何:调试 .NET Framework 源代码

?按照文章内容,还是没有进入dll文件的方法,不知道为什么。

?

文章:https://m.zs-baili.com/zh-cn/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box?view=vs-2017

标题:“解决方案属性页”对话框 ->“通用属性”->“调试源文件”

还是没有进展。

?

文章:https://m.zs-baili.com/forums/vstudio/en-US/1d3c5a9a-7334-4476-8467-327fff6bb01b/1-how-do-i-configure-visual-studio-to-debug-net-framework-source-code

标题:1.如何配置Visual Studio以调试.NET Framework源代码?

?博客:http://m.zs-baili.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

不知道为什么没有起效。

按照这个设置起作用了,不过有的地方没有源代码,调试起来很费劲。

?

标题:How do I debug .NET 4.6 framework source code in Visual Studio 2017?

文章:How to configure Visual Studio for debugging .NET framework

地址:https://m.zs-baili.com

第二篇文章有可靠的介绍!

?

微博http://m.zs-baili.com/docker/2017/04/06/NET-Framework-Open-Source-ILSpy.html

m.zs-baili.com源代码?Viewing .NET Framework Source Code - Open Source or Closed with ILSpy and Visual Studio

?

?

==============================================

文章:Visual Studio(VS) F12 查看DLL源代码

这篇文章介绍了安装Resharp达到目的,同时vs2017已经自带这个功能;

工具>选项>文本编辑器>c#>高级>启用导航到反编译源

?

============================================

总结:最后也能f11进源代码了,几个关键点需要注意:

第一,常规项下:

0,关闭 启用“仅我的代码”(设置了第2条,会自动关闭);

1,启用源服务器支持;

2,启用.NET Framework源代码单步调试;

第二,符号项下:

选中:Microsoft符号服务器

增加:http://m.zs-baili.com/symbols

增加:D:/DebugFuHaoCache,自己设置的符号缓存位置

?

然后启用调试,等符号下载完毕后,就可以调试进源代码了。下载符号大概需要10分钟。

?

转载于:https://m.zs-baili.com/Tpf386/p/10232217.html

注:

? DLL:表示链接库,包含dll,lib文件;

? dll: 表示my.dll文件

? lib: 表示my.lib文件

?

C++ 调用.lib的方法:

一: 隐式的加载时链接,有三种方法

  1? 设置工程的 Projects来加载DLL的lib文件

  打开工程的 Projects菜单,然后在Linker/Additional Library Directories中加入lib文件所在的路径,在Input/Additional?Dependencies加入lib文件名称,如(my.lib)?,然后在要使用该函数的地方加上该LIB的头文件,如#include "..\lib.h"即可(没有头文件当然就不用了),而且应用程序运行时也需要dll文件。

  32 通过程序代码的方式

  加入预编译指令#pragma comment (lib,"*.lib"),这种方法优点是可以利用条件预编译指令链接不同版本的LIB文件。因为,在Debug方式下,产生的LIB文件是Debug版本,如Regd.lib;在Release方式下,产生的LIB文件是Release版本,如Regr.lib。然后在首先要使用该函数的地方加上该LIB的头文件,如#include "..\lib.h"即可(没有头文件当然就不用了)。

当应用程序对链接库的LIB文件加载后,还需要把链接库对应的头文件(*.h)包含到其中,在这个头文件中给出了链接库中定义的函数原型。

二, 显式的调用链接库 隐式链接虽然实现较简单,但除了必须的*.dll文件外还需要DLL的*.h文件和*.lib文件,在那些只提供*.dll文件的场合就无法使用,而只能采用显式链接的方式。这种方式通过调用API函数来完成对DLL的加载与卸载,能更加有效地使用内存,在编写大型应用程序时往往采用此方式。这种方法编程具体实现步骤如下: ①使用Windows API函数Load Library或者MFC提供的AfxLoadLibrary将DLL模块映像到进程的内存空间,对DLL模块进行动态加载。 ②使用GetProcAddress函数得到要调用DLL中的函数的指针。 ③不用DLL时,用Free Library函数或者AfxFreeLibrary函数从进程的地址空间显式卸载DLL。 例:在应用程序中调用dll文件

——在应用程序中要首先装入dll后才能调用导出表中的函数,例如用mfc

?

创建基于对话框的工程test,并在对话框上放置"load"按钮,先添加装载代码。 1.首先在testdlg.cpp的首部添加变量设置代码:

//设置全局变量glibsample用于存储dll句柄

HINSTANCE? glibsample=null;?? //如果定义成HANDLE类型,则出错

//第二个变量showme是指向dll 库中showme()函数的指针

typedef int(* Showme)(void);

Showme showme;

?

2.利用classwizard为"load"按钮添加装载dll的代码

void ctestdlg::onloadbutton()

{

//要添加的代码如下

if(glibsample!=NULL)

{

AfxMessageBox("the sample.dll has already been load.");

return;

}

//装载sample.dll,未加路径,将在三个默认路径中寻找 (1)windows的系统目录:\windows\system;

//(2)dos中path所指出的任何目录;

//(3)程序所在的目录;

glibsample=Loadlibrary("sample.dll");

//返回dll中showme()函数的地址

showme=(Showme)GetProcAddress(glibsample,"showme");

?

静态链接库LIB和动态链接库DLL的区别

1.什么是静态连接库,什么是动态链接库 ????? 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。静态链接库与静态链接库调用规则总体比较如下。

对于静态链接库(比较简单): 首先,静态链接库的使用需要库的开发者提供生成库的.h头文件和.lib文件,应用程序运行时还依赖.dll文件。

生成库的.h头文件中的声明格式如下: extern "C" 函数返回类型 函数名(参数表); 在调用程序的.cpp源代码文件中如下: #include "..\lib.h" #pragma comment(lib,"..\\debug\\libTest.lib") //指定与静态库一起链接

第二,因为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想用就得全要!要不就都别要!:)

对于动态链接库: 动态链接库的使用需要库的开发者提供生成的.lib文件,.dll文件和*.h文件或者只提供dll和*.h文件。

*.h文件主要是知道函数原型使用。 首先我们必须先注意到DLL内的函数分为两种: (1)DLL 导出函数,可供应用程序调用; (2)DLL 内部函数,只能在 DLL 程序使用,应用程序无法调用它们。 因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想调用哪一个函数。

?

http://m.zs-baili.com/s/blog_a50d2d740101fwuq.html

?

一、为什么需要dll

代码复用是提高软件开发效率的重要途径。一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用。

比较常见的例子是各种应用程序框架,如ATL、MFC等,它们都以源代码的形式发布。由于这种复用是“源码级别”的,源代码完全暴露给了程序员,因

而称之为“白盒复用”。“白盒复用”的缺点比较多,总结起来有4点。

暴露了源代码;容易与程序员的“普通”代码发生命名冲突;多份拷贝,造成存储浪费;更新功能模块比较困难。

实际上,以上4点概括起来就是“暴露的源代码”造成“代码严重耦合”。为了弥补这些不足,就提出了“二进制级别”的代码复用。使用二进制级别的代码复用

一定程度上隐藏了源代码,对于缓解代码耦合现象起到了一定的作用。这样的复用被称为“黑盒复用”。

在Windows操作系统中有两种可执行文件,其后缀名分别为.exe和.dll。它们的区别在于,.exe文件可被独立的装载于内存中运行;.dll文件却不能,它只能被

其它进程调用。然而无论什么格式,它们都是二进制文件。上面说到的“二进制级别”的代码复用,可以使用.dll来实现。

与白盒复用相比,.dll很大程度上弥补了上述4大缺陷。.dll是二进制文件,因此隐藏了源代码;如果采用“显式调用”(后边将会提到),一般不会发生命名冲

突;由于.dll是动态链接到应用程序中去的,它并不会在链接生成程序时被原原本本拷贝进去;.dll文件相对独立的存在,因此更新功能模块是可行的。

说明:实现“黑盒复用”的途径不只dll一种,静态链接库甚至更高级的COM组件都是。本文只对dll进行讨论。

二、创建dll

接下来用一个简单的例子来说明创建dll的方法。本例采用VS2010,使用C++编程语言,具体操作步骤如下。

通过Start Page或者File菜单栏,新建一个Project,将会弹出新建项目对话框。选择Win32 Project向导,项目名为CreateDLL,解决方案名为DLLTEST(注意

Create directories for solution是勾选上的),点击OK,接着点击Next,到Application Settings,选择应用程序类型为dll,并勾选“Export Symbols”,点击Finish。

完成这一步之后,VS界面上左边的Solution Explorer中将会看到向导自动生成的文件列表,如图1所示。

图1 wizard自动生成的文件列表

在VS界面的编辑窗口中,展示了自动生成的CreateDLL.cpp的代码。

//?CreateDLL.cpp?:?Defines?the?exported?functions?for?the?DLL?application.??//????#include?"stdafx.h"??#include?"CreateDLL.h"??????//?This?is?an?example?of?an?exported?variable??CREATEDLL_API?int?nCreateDLL?=?0;????//?This?is?an?example?of?an?exported?function.??CREATEDLL_API?int?fnCreateDLL(void)??{??????return?42;??}????//?This?is?the?constructor?of?a?class?that?has?been?exported.??//?see?CreateDLL.h?for?the?class?definition??CCreateDLL::CCreateDLL()??{??????return;??}??

这里有3种类型的example,分别为导出变量nCreateDLL、导出函数fnCreateDLL以及导出类CCreateDLL。为了简化起见,本例只考虑导出函数。

修改CreateDLL.h文件为:

#ifdef?CREATEDLL_EXPORTS??#define?CREATEDLL_API?__declspec(dllexport)??#else??#define?CREATEDLL_API?__declspec(dllimport)??#endif????CREATEDLL_API?void?printMax(int&,int&);??CREATEDLL_API?void?printMax(int&,int&,int&);??

修改CreateDLL.cpp文件为:?

CREATEDLL_API?void?printMax(int&?a,int&?b)??{??????std::cout<<"Among?("<b?a:b)<<"\n";??}??CREATEDLL_API?void?printMax(int&?a,int&?b,int&?c)??{??????std::cout<<"Among?("<b?a:b)>c)?(a>b?a:b):c)<<"\n";??}??

不难发现,printMax函数的作用就是打印出两个整数或三个整数中的最大值。需要说明的是,这里故意使用同名函数是为了引出导出函数的修饰名称,

具体将在第四节中阐述。

接下来,选择菜单Build->Build CreateDLL,Output窗口提示CreateDLL.dll文件生成成功,如图2所示。

?图2 CreateDLL.dll成功生成

三、使用dll

本例采用“显式调用”的方式使用CreateDLL.dll。显式调用方式相比于”隐式调用“有好有坏。显式调用只需要一个.dll文件就可以了,灵活性更好,

更新模块方便;相对的,程序员需要做的事情更多,使用方法更为复杂。

右键单击Solution Explorer中的Solution 'DLLTEST',在弹出的菜单中选择Add->New Project,选择Win32 Console Application,输入项目名为UseDLL,

点击OK,接着点击Next,在Application Settings界面勾选EmptyProject并点击Finish。右键单击项目UseDLL,给它添加源文件UseDLL.cpp。这样操

作之后,Solution Explorer的信息如图3所示。

图3 向Solution'DLLTEST'添加项目UseDLL

编写UseDLL.cpp的代码为:

/*--UseDLL.cpp??*Author:?ume(李优米)??*Use?CreateDLL.dll?explicitly??*/??#include??#include??typedef?void(*FUNA)(int&,int&);??typedef?void(*FUNB)(int&,int&,int&);??int?main()??{??????const?char*?dllName?=?"CreateDLL.dll";??????const?char*?funName1?=?"printMax";??????const?char*?funName2?=?"printMax";??????int?x(100),?y(100),?z(100);??????HMODULE?hDLL?=?LoadLibrary(dllName);??????if(hDLL?!=?NULL)??????{??????????FUNA?fp1?=?FUNA(GetProcAddress(hDLL,funName1));??????????if(fp1?!=?NULL)??????????{??????????????std::cout<<"Input?2?Numbers:";??????????????std::cin>>x>>y;??????????????fp1(x,y);??????????}??????????else??????????{??????????????std::cout<<"Cannot?Find?Function?"<>x>>y>>z;??????????????fp2(x,y,z);??????????}??????????else??????????{??????????????std::cout<<"Cannot?Find?Function?"<

代码比较长,但是并不难理解,这里仅说明代码中的一些要点。

包含头文件Windows.h,原因在于程序中用到了LoadLibrary、FreeLibrary、GetProcAddress等Win32 API函数。FUNA和FUNB是函数指针类型的声明。当程序不再使用dll时,应该调用FreeLibrary及时释放它占用的内存空间。如果在const char* dllName和funName底部出现红色波浪线提示,说明采用的字符集不匹配,需要修改项目UseDLL的属性CharaterSet为Not Set。为方便项目的调试,建议修改解决方案的Startup Project属性为Single startup project并以UseDLL为首选。

然而,这个程序还有错误。编译并运行,结果如图4所示。

????????????????图4 UseDLL的运行结果

这并不是期望中的结果。实际上,正如第二节提到的那样,造成这种错误的原因正是导出函数的修饰名称。虽然在CreateDLL.cpp中两个printMax函数

有相同的名称,但在dll二进制文件中,经过编译器的“加工”,它们实际上各自有不同的名称了。这也是函数重载机制得以实现的一个技术支持。

使用VS2010附带工具dumpbin,查看CreateDLL.dll的导出函数名,结果如图5所示。

?图5 查看CreateDLL.dll的导出函数名

观察图5可以发现,CreateDLL.dll导出函数名为?printMax@@YAXAAH00@Z和?printMax@@YAXAAH0@Z。它们分别对应着三个整数的printMax

和两个整数的printMax。因此,Use.DLL中funName应当相应修改为:

const?char*?funName1?=?"?printMax@@YAXAAH0@Z";??const?char*?funName2?=?“?printMax@@YAXAAH00@Z”;??

修改之后,再次编译运行,结果正确,如图6所示。

?图6 UseDLL正常运行

四、dll导出函数名称规范化

创建、使用dll并不复杂,走过前三节,相信读者肯定有这样的体会。然而,一个问题仍然值得思考:导出函数的修饰名称太“奇怪”,

为dll的使用带来了不便,能不能让导出函数的修饰名称规范一些?答案是肯定的,而且方法至少有两种:一是运用extern "C"修饰printMax;

二是运用模块定义文件.def。后者的效果更好,所以本节将使用.def来规范化导出函数的修饰名称。

CreateDLL.dll导出的两个函数功能很简单,根据功能描述,理想的函数名称是pMaxA2和pMaxA3。在CreateDLL项目中添加CreateDLL.def文件:

LIBRARY?CreateDLL??EXPORTS??pMaxA2?=??printMax@@YAXAAH0@Z??pMaxA3?=??printMax@@YAXAAH00@Z??

重新build项目CreateDLL,使用dumpbin再次查看CreateDLL.dll的导出函数名称,结果如图7所示。

图7 规范化的函数名,奇怪的修饰名称还存在

出现了期望的结果,但仍有小缺憾:奇怪的修饰名称仍然存在。能否去掉这些不太规范的修饰名称呢?当然是可以的。只需要将CreateDLL.h

中#define CREATEDLL_API __declspec(dllexport)?修改为#define CREATEDLL_API即可。修改之后重新编译生成CreateDLL.dll,使用dumpbin

查看导出函数名称,结果如图8所示。

图8 规范化的函数名,去除了奇怪的修饰名称????

回到UseDLL.cpp,修改funName:

const?char*?funName1?=?"pMaxA2";??const?char*?funName2?=?"pMaxA3";??

重新编译运行UseDLL,结果正确,与图6类似。五、dll的不足

动态链接库虽然一定程度上实现了“黑盒复用”,但仍存在着诸多不足,笔者能够想到的有下面几点。

dll节省了编译期的时间,但相应延长了运行期的时间,因为在使用dll的导出函数时,不但要加载dll,而且程序将会在模块间跳转,降低了cache的命中率。若采用隐式调用,仍然需要.h、.lib、.dll文件(“三件套”),并不能有效支持模块的更新。显式调用虽然很好地支持模块的更新,但却不能导出类和变量。dll不支持Template。

二进制级别的代码复用相比源码级别的复用已经有了很大的进步,但在二进制级别的代码复用中,dll显得太古老。想真正完美实现跨平台、

跨语言的黑盒复用,采用COM才是正确的选择。

?

http://m.zs-baili.com/wondergdf/article/details/7870491?reload

关灯