我总是在我的C#代码中引用DLL,但它们仍然有些神秘,我想澄清一下 . 这是关于DLL的问题的一种大脑转储 .
我理解DLL是一个动态链接库,这意味着另一个程序可以在运行时访问该库以获取"functionality" . 但是,请考虑以下带有 Web.dll
和 Business.dll
的ASP.NET项目( Web.dll
是前端功能,它为类型和方法引用 Business.dll
) .
Web.dll
在什么时候动态链接到Business.dll
?在使用Word(等)时,你会注意到很多Windows硬盘驱动程序看似小的任务,我认为Word正在关闭并动态链接其他DLL的功能?
1A . 另外,什么加载和链接DLL - 操作系统或某些运行时框架,如.NET框架?
1B . 什么是“链接”的过程?是否进行兼容性检查?加载到同一个内存?链接实际意味着什么?
- 实际执行DLL中的代码是什么?它是由处理器执行还是在处理器理解DLL中的代码之前还有另一个转换或编译阶段?
2A . 对于使用C#.NET构建的DLL,运行它的是什么:.NET框架或操作系统直接?
-
Linux中的DLL是否可以在Windows系统上运行(如果存在这样的事情),或者它们是否特定于操作系统?
-
DLL是否特定于特定框架?使用C#.NET构建的DLL是否可以由使用Borland C构建的DLL使用?
4A . 如果4的答案是“否”那么DLL的重点是什么?为什么各种框架不使用自己的格式来链接文件?例如:.NET内置的.exe知道.abc的文件类型可以链接到其代码中 .
- 回到
Web.dll
/Business.dll
示例 - 要获得类型的客户,我需要从Web.dll
引用Business.dll
. 这必须意味着Business.dll
包含某种关于客户类实际是什么的规范 . 如果我已经编译了我的Business.dll
文件,比如Delphi:C#会理解它并且能够创建一个客户类,还是有某种 Headers 信息或者说"hey sorry you can only use me from another Delphi DLL"?
5A . 同样适用于方法;我可以在DLL中编写 CreateInvoice()
方法,在C中编译它,然后从C#访问并运行它吗?什么阻止或允许我这样做?
- 关于DLL劫持的问题,当然,替换(坏)DLL必须包含与被劫持的精确方法签名和类型 . 我想如果你能找到原始DLL中可用的方法,那就不难做到 .
6A . 在我的C#程序中决定我是否可以访问另一个DLL?如果我的被劫持的DLL包含与原始DLL完全相同的方法和类型但是它是用另一种语言编译的,它会起作用吗?
什么是DLL导入和DLL注册?
3 回答
首先,您需要了解两种非常不同的DLL之间的区别 . Microsoft决定使用相同的文件扩展名(.exe和.dll)同时使用.NET(托管代码)和本机代码,但托管代码DLL和本机DLL在内部非常不同 .
1)在.NET的情况下,当执行尝试从DLL访问任何内容的第一个方法时,通常按需加载DLL . 这就是为什么如果无法加载DLL,您可以在代码中的任何位置获取TypeNotFoundExceptions . 当像Word这样的东西突然开始大量访问硬盘时,它可能会交换(将已交换到磁盘的数据转换为在RAM中腾出空间)
1a)在托管DLL的情况下,.NET框架是加载,JIT编译(将.NET字节码编译成本机代码)并链接DLL . 在本机DLL的情况下,它是操作系统的一个组件,用于加载和链接DLL(不需要编译,因为本机DLL已经包含本机代码) .
1b)链接是当调用代码中的引用(例如方法调用)到DLL中的符号(例如方法)被DLL中的事物的实际地址替换时 . 这是必要的,因为在将DLL加载到内存之前,无法知道DLL中事物的最终地址 .
2)在Windows上,.exe文件和.dll文件完全相同 . 原生.exe和.dll文件包含本机代码(处理器执行的相同内容),因此无需翻译 . 托管的.exe和.dll文件包含.NET字节码,这是第一次JIT编译(翻译成本机代码) .
2a)代码经过JIT编译后,它的运行方式与任何代码完全相同 .
3)托管DLL可以按原样工作,只要两个平台上的框架都是最新的,并且编写DLL的人不会故意通过使用本机调用来破坏兼容性 . 由于格式不同,原生DLL将无法正常工作(即使内部的机器代码相同,如果它们都是相同的处理器平台) . 顺便说一句,在Linux上,“DLL”被称为.so(共享对象)文件 .
4)托管DLL是.NET框架特有的,但自然它们可以与任何兼容的语言一起使用 . 只要每个人都使用相同的约定(调用约定(如何在机器代码级别传递函数参数),符号命名等),本机DLL是兼容的
5)托管DLL包含它们包含的每个类,方法,字段等的完整描述 . AFAIK Delphi不支持.NET,因此它会创建本机DLL,而这些DLL不能直接在.NET中使用 . 您可能能够使用PInvoke调用函数,但找不到类定义 . 我不使用Delphi,所以我不知道它如何存储DLL的类型信息 . 例如,C依赖于包含类型声明的头(.h)文件,并且必须随DLL一起分发 .
6)实际上,如果你可以轻松切换DLL,这并不难 . 代码签名可用于避免这种情况 . 为了让某人替换已签名的DLL,他们必须知道签名密钥,它保密 .
6a)它可以工作,只要它是一个托管DLL,用任何.NET语言编写 .
“DLL导入”可能意味着很多东西,通常意味着引用DLL文件并使用其中的内容 .
DLL注册是在Windows上完成的,它将DLL文件全局注册为COM组件,以使它们可供系统上的任何软件使用 .
.dll文件包含可在应用程序中使用的已编译代码 .
有时,用于编译.dll的工具很重要,有时则不然 . 如果您可以在项目中引用.dll,那么使用哪个工具来编写.dll的公开函数并不重要 .
链接发生在运行时,不像静态链接的库,例如链接到的类编译时间 .
您可以将.dll视为一个黑盒子,它提供您不希望自己编写的应用程序所需的内容 . 是的,有人理解.dll的签名可能会创建另一个包含不同代码的.dll文件,并且您的调用应用程序无法知道其中的差异 .
HTH
1)我认为你混淆加载链接 . 链接是在测试所有检查和 balancer 时确保所要求的内容可用 . 在加载时,部分dll被加载到内存中或换出到页面文件 . 这是您看到的高清活动 .
动态链接与静态链接的不同之处在于,在静态链接中,所有目标代码都在链接时放入主.exe中 . 通过动态链接,目标代码被放入一个单独的文件(dll)中,并在与.exe不同的时间加载 .
动态链接可以是隐式的(即应用程序与导入库链接)或显式(即应用程序使用LoadLibrary(ex)加载dll) .
在隐式的情况下,/ DELAYLOAD可用于推迟加载dll,直到应用程序实际需要它为止 . 否则,作为进程初始化的一部分,至少将其一部分加载(映射到进程地址空间) . dll还可以请求在进程处于活动状态时永远不会卸载它 .
COM使用LoadLibrary加载COM dll . 请注意,即使在隐式情况下,系统也会使用与LoadLibrary类似的内容在进程启动时或首次使用时加载dll .
2)Dll包含与.exes类似的对象代码 . dll文件的格式几乎与exe文件的格式相同 . 我听说在两个文件的 Headers 中只有一个不同的位 .
对于使用C#.net构建的DLL,.Net框架正在运行它 .
3)DLL是特定于平台的 .
4)如果采取特殊措施或编写一些额外的胶水代码,Dll可以与其他框架互操作 .
当公司销售具有重叠功能的多个产品时,Dll非常有用 . 例如,我维护一个光栅i / o dll,该公司使用了30多种不同的产品 . 如果您安装了多个产品,则dll的一次升级可以将所有产品升级为新的栅格格式 .
5)根据平台的不同,dll的功能以各种方式呈现,通过.h文件,.tlb文件或.net上的其他方式 .
6)dumpbin / exports和dumbin / imports是在.exe和.dll上使用的有趣工具