一、非托管动态链接库
1、非托管动态链接库(Unmanaged Dynamic Link Library,简称DLL)
是一种包含可执行代码和数据的二进制文件,它被设计为在操作系统级别上执行。与托管代码不同,非托管DLL是使用原生机器代码编写的,并且不依赖于特定的运行时环境(如.NET Framework或.NET Core)。
非托管DLL通常由C、C++或其他低级语言编写,并且可以在多个编程语言和平台上使用。它们提供了对操作系统API、硬件驱动程序和其他系统级功能的访问。
2、使用非托管DLL可以实现以下功能:
(1)访问操作系统级别的功能:
非托管DLL可以直接调用操作系统提供的API,访问底层功能,如文件操作、网络通信、图形处理等。
(2)调用硬件驱动程序:
非托管DLL可以与硬件设备进行交互,如打印机、摄像头、传感器等。
(3)提供性能优势:
由于非托管DLL是使用原生机器代码编写的,它们通常比托管代码执行速度更快,对于对性能要求较高的任务,可以使用非托管DLL来实现。
3、在使用非托管DLL时,需要注意以下几点:
(1)平台兼容性:
非托管DLL是特定于操作系统和硬件平台的,因此需要根据目标平台选择正确的DLL版本。
(2)内存管理:
非托管DLL使用自己的内存管理机制,可能需要手动分配和释放内存,需要小心处理内存泄漏和访问冲突的问题。
(3)安全性:
非托管DLL可以直接访问系统资源,因此需要小心处理安全性问题,避免潜在的漏洞和攻击。
总之,非托管动态链接库是一种使用原生机器代码编写的二进制文件,用于访问操作系统级别的功能和提供性能优势。它们在许多编程语言和平台上都有广泛的应用。
二、user32.dll
1、user32.dll是Windows操作系统中的一个非托管动态链接库(DLL),它包含了许多用户界面相关的函数和功能。
在C#中,我们可以使用P/Invoke机制来访问和调用user32.dll中的函数。通过在C#代码中声明这些函数的签名,并使用 DllImport 特性来指定user32.dll的路径和函数名,我们可以在C#中调用user32.dll中的函数。
这样,我们可以使用user32.dll提供的函数来实现与用户界面相关的操作,如创建和管理窗口、处理鼠标和键盘输入、显示消息框等。user32.dll是Windows操作系统的一部分,因此它在所有安装了Windows的计算机上都可用。
2、在 Windows 系统中,user32.dll 文件通常位于以下目录之一:
C:\Windows\System32:这是最常见的 DLL 文件存放目录,包含了许多系统级别的 DLL 文件。
C:\Windows\SysWOW64:这是用于存放 32 位应用程序所需的 32 位 DLL 文件的目录。请注意,即使在 64 位系统上,32 位应用程序仍然使用这个目录来查找其所需的 32 位 DLL 文件。
不同版本目录位置不同。
三、如何调用非托管动态链接库
1、C#中使用非托管动态链接库(DLL),您可以使用平台调用(Platform Invocation Services,简称P/Invoke)机制。下面是使用P/Invoke的一般步骤:
(1)导入DLL:使用 DllImport 特性声明非托管DLL中的函数。在特性中,指定DLL的路径和函数名。
[DllImport("yourDLL.dll")]
public static extern returnType functionName(parameters);
(2)声明函数签名:在C#代码中声明与非托管DLL中函数相对应的函数签名。确保参数类型和返回类型与DLL中的函数匹配。
public static extern returnType functionName(parameters);
(3)调用函数:在C#代码中调用声明的函数。
returnType result = functionName(arguments);
2、注意事项:
-
非托管DLL的路径应该是绝对路径或者位于系统路径(如Windows\System32)下。
-
参数和返回类型应该与非托管DLL中函数的定义一致。
-
非托管DLL中函数的调用约定(calling convention)可能需要进行显式的指定,如 StdCall 或 Cdecl。
需要注意的是,使用非托管DLL需要小心处理内存管理、安全性和平台兼容性等问题。确保正确释放内存、处理异常和错误,并确保在不同的操作系统和体系结构上都能正常工作。
另外,有些非托管DLL可能提供了专门为C#等托管语言编写的托管包装器DLL,这些包装器DLL提供了更方便的面向对象的API,可以更容易地与非托管DLL进行交互。在这种情况下,您可以直接引用这些托管包装器DLL,而不需要使用P/Invoke来调用非托管DLL中的函数。
总结起来,使用P/Invoke机制可以在C#中访问和调用非托管动态链接库中的函数。通过声明函数签名,并使用 DllImport 特性指定DLL的路径和函数名,您可以在C#代码中调用非托管DLL中的函数。
四、实例
1、模拟按下Alt+Tab键
cs
/// <summary>
///
/// </summary>
/// <param name="bVk">模拟的键</param>
/// <param name="bScan">保留参数,0</param>
/// <param name="dwFlags">按键标志,0按下,2释放</param>
/// <param name="dwExtraInfo">保留,0用(UIntPtr.Zero)表示</param>
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
private void BtnStart_Click(object sender, EventArgs e)
{
keybd_event((byte)Keys.Menu, 0, 0, UIntPtr.Zero);//按下alt
keybd_event((byte)Keys.Tab, 0, 0, UIntPtr.Zero);//按下tab
keybd_event((byte)Keys.Menu, 0, 2, UIntPtr.Zero);//松开alt
keybd_event((byte)Keys.Tab, 0, 2, UIntPtr.Zero);//松开tal
}
2、什么是extern?
extern用于声明一个外部方法。它通常用于与非托管代码(如C/C++)进行交互,以便在C#中调用非托管代码中的函数。
使用extern关键字可以将非托管函数的声明引入到C#代码中,以便在C#中调用该函数。声明外部函数时,需要使用DllImport特性来指定非托管库的名称和其他相关信息。
3、Keys.Menu与Keys.Alt的区别?
两者实则是一个键,在表示单一键时,用Keys.Menu;在表示组合(与Ctrl,Shift)时,用Keys.Alt,此时被视为修饰键。
4、UIntPtr是什么?
UIntPtr是一个结构体,用于表示一个指针或句柄的无符号整数。它可以用来表示指针或句柄的值,而无需关心具体的平台和指针的大小。UIntPtr的大小和指针的大小是平台相关的。在32位系统上,UIntPtr的大小为4字节,在64位系统上,UIntPtr的大小为8字节。
在非托管的DLL中,当需要传递一个空指针或无效句柄时,可以使用UIntPtr.Zero来表示。UIntPtr.Zero是一个UIntPtr类型的静态字段,它的值为0,可以用于表示空指针或无效句柄。
在非托管代码中,通常会使用整数类型(如int或IntPtr)来表示指针或句柄。当需要传递一个空指针或无效句柄时,可以将整数值设置为0。在C#中,可以使用UIntPtr.Zero来表示这个整数值为0的指针或句柄。
五、excel的dll引用
非托管动态链接库是不能直接引用的,但为什么excel的dll是可以引用的?
非托管动态链接库(DLL)是不能直接在C#代码中引用的。C#是一种托管语言,它运行在托管环境中,而非托管DLL是使用其他编程语言(如C++)编写的,并且运行在非托管环境中。要在C#代码中使用非托管DLL中的函数,需要使用DllImport特性和extern关键字来声明外部方法。
然而,有一些特定的非托管DLL,如Excel的DLL(例如"Interop.Excel.dll"),它们是由Microsoft提供的专门用于与Excel进行交互的托管包装器。这些托管包装器DLL是使用C#或其他托管语言编写的,它们封装了与Excel交互所需的COM接口和功能,并提供了更方便的面向对象的API供C#开发人员使用。
因此,当我们在C#项目中引用Excel的DLL时,实际上是引用了这些托管包装器DLL,而不是直接引用非托管DLL。这些托管包装器DLL已经处理了与非托管DLL的交互细节,并提供了更高级别的API,使我们可以更轻松地与Excel进行交互。
总结,虽然非托管DLL一般需要通过P/Invoke机制来访问和调用,但某些特定的非托管DLL,如Excel的DLL,可以通过引用托管包装器DLL来提供更方便的API和交互方式。这样,我们可以直接在C#代码中使用这些托管包装器DLL提供的功能,而不需要手动进行P/Invoke调用。
P/Invoke(Platform Invocation Services):
是一种在.NET平台上调用非托管代码的技术。它允许.NET应用程序使用DllImport属性和相关的DllImport函数来调用C/C++等非托管代码中的函数。
通过P/Invoke,可以在.NET应用程序中直接调用非托管动态链接库(DLL)中的函数。这对于需要访问操作系统API、硬件驱动程序或其他原生代码的情况非常有用。