DLL与应用程序

动态链接库(也称为DLL,即为“Dynamic Link Library”的缩写)是Microsoft Windows最重要的组成要素之一,打开Windows系统文件夹,你会发现文件夹中有很多DLL文件,Windows就是将一些主要的系统功能以DLL模块的形式实现。

动态链接库是不能直接执行的,也不能接收消息,它只是一个独立的文件,其中包含能被程序或其它DLL调用来完成一定操作的函数(方法。注:C#中一般称为“方法”),但这些函数不是执行程序本身的一部分,而是根据进程的需要按需载入,此时才能发挥作用。

DLL只有在应用程序需要时才被系统加载到进程的虚拟空间中,成为调用进程的一部分,此时该DLL也只能被该进程的线程访问,它的句柄可以被调用进程所使用,而调用进程的句柄也可以被该DLL所使用。在内存中,一个DLL只有一个实例,且它的编制与具体的编程语言和编译器都没有关系,所以可以通过DLL来实现混合语言编程。DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。

下面列出了当程序使用 DLL 时提供的一些优点:

1) 使用较少的资源

当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows 操作系统上运行的程序。

2) 推广模块式体系结构

DLL 有助于促进模块式程序的开发。这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。模块式程序的一个示例是具有多个可以在运行时动态加载的模块的计帐程序。

3) 简化部署和安装

当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地出现。

1. 托管代码与非托管代码

在学习DllImport方法之前,先了解下托管代码和非托管代码的概念。

我们编写的C#代码(不只是C#,也包括.net平台上的其他语言,如VB,J#等),首先经过编译器把代码编译成中间语言(IL),当方法被调用时,公共语言运行库CLR把具体的方法编译成适合本地计算机运行的机器码,并且将编译好的机器码缓存起来,以备下次调用使用。

托管代码的源代码在运行时分为两个阶段:

源代码编译为托管代码,(源代码可以有很多种,如VB,C#,J#)
托管代码编译为microsoft的平台专用语言,也叫机器代码
非托管代码,是运行在公共语言运行库环境的外部,直接编译成目标计算机码,由操作系统直接执行的代码,代码必须自己提供垃圾回收,类型检查,安全支持等服务。如需要内存管理等服务,必须显示调用操作系统的接口,通常调用Windows SDK所提供的API来实现内存管理。

托管代码和非托管代码的区别

1、托管代码是一种中间语言,运行在CLR上;非托管代码被编译为机器码,运行在机器上。

2、托管代码独立于平台和语言,能更好的实现不同语言平台之间的兼容;非托管代码依赖于平台和语言。

3、托管代码可享受CLR提供的服务(如安全检测、垃圾回收等),不需要自己完成这些操作;非托管代码需要自己提供安全检测、垃圾回收等操作。

2.Dll文件的使用

DLL文件是动态链接库,也叫程序集,是一个包含可由多个程序,同时使用的代码和数据的库。

程序集是在 .NET 公共语言运行库 (CLR) 控制之下运行的逻辑功能单元。程序集实际上是作为 .dll 文件或 .exe 文件存在的。

托管代码生成的DLL文件,可以在VS中直接通过添加引用的方式使用。

非托管代码生成的DLL文件,比如使用C++编写的代码编译生成的DLL,不能在VS中直接引用,可以通过DllImport方法来使用。

3.DllImport的基本使用

DllImport是System.Runtime.InteropServices命名空间下的一个属性类,其功能是提供从非托管DLL导出函数的必要调用信息。

其中,引入到C#中的只能是非托管dll中的方法(或者说函数),而不能是数据(或者说变量)

(1)引入命名空间

using System.Runtime.InteropServices;

(2)创建函数名称

[DllImport("demo.dll")]
public static extern bool OpenDemo();

其中:

修饰符staticextern是必不可少的(extern外部修饰符,常与DllImport属性一起使用,用于支持在外部实现方法)

最少要提供包含入口点的dll的名称

(3)DllImportAttribute属性用法

[AttributeUsage(AttributeTargets.Method)]
public class DllImportAttribute: System.Attribute
{
   public DllImportAttribute(string dllName) {}    //定位参数为dllName
   public CallingConvention CallingConvention;      //入口点调用约定
   public CharSet CharSet;                              //入口点采用的字符接
   public string EntryPoint;                //入口点名称
   public bool ExactSpelling;               //是否必须与指示的入口点拼写完全一致,默认false
   public bool PreserveSig;                 //方法的签名是被保留还是被转换
   public bool SetLastError;                //FindLastError方法的返回值保存在这里
   public string Value { get {} }
}

4.DllImport详解

DllImport的使用规范:

(1)DllImport只能放置在方法声明上。
(2)DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。
(3)DllImport具有五个命名参数:
 a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。
 b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。
 c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。
 d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。
 e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。
 f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。
(4)它是一次性属性类。
(5)此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

Dll引用路径

(1)exe运行程序所在的目录

(2)System32目录

(3)环境变量目录

(4)自定义路径,如:DllImport(@“C:\OJ\Bin\Judge.dll”)

5.常用DLL

一、User32.dll

user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。

User32.dll 是 Windows 图形用户界面的主要支持。一些重要的图形用户界面函数由 User32.dll 函数导出。

二、Kernel32

(1)Kernel32介绍

Kernel32.dll是一个Windows操作系统的核心动态链接库文件。它位于Windows系统目录下,并提供了大量的API函数,提供了操作系统的基本功能。

Kernel32.dll提供了许多不同类型的函数,它们都有着各自不同的用途。例如,Kernel32.dll中包含了文件管理相关的函数,可以用来创建、打开、读写、关闭文件。此外,Kernel32.dll还包含了内存管理相关的函数,可以用来分配、释放、移动内存。此外,Kernel32.dll还提供了许多其他类型的函数,如线程管理、进程管理、调试、错误处理、时间处理等。

Kernel32.dll是Windows操作系统的一个重要组成部分,它提供了大量的API函数,为应用程序提供了与操作系统交互的方法。通过调用Kernel32.dll中的函数,应用程序可以实现许多有用的功能,比如读写文件、管理内存、管理线程等。

(2)、Kernel32内存管理

Kernel32.dll包含各种用于管理Windows操作系统内存的函数。例如,GlobalAlloc和LocalAlloc函数用于从堆中分配内存,而GlobalFree和LocalFree函数则用于释放先前分配的内存。VirtualAlloc和VirtualFree函数用于分配和释放进程的虚拟地址空间中的内存,而HeapAlloc和HeapFree函数则用于管理私有堆中的内存。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐