托管与非托管
1、托管与非托管
1.1、公共语言运行时-CLR
CLR是.Net运行环境,在运行期管理程序的执行,主要包含:内存管理、代码安全验证、代码执行、垃圾收集等。
1.2、托管代码和非托管代码
所谓托管代码,即可以通过CLR的GC来释放所有资源的代码,开发者无需过度关注资源的释放。而至于非托管代码,比如操作系统代码、C#中的Socket、Stream等,这些代码无法通过CLR的CG完全释放占用的资源。一般来说,非托管的功能都被包装过了,比如当我们访问文件的时候,肯定不会直接使用操作系统的CreateFile函数,而是使用System.IO.File类。让用户直接使用的非托管功能确实非常少见。由于CLR提供了垃圾收集,随之带来的一个特性就是内存安全。所谓内存安全,即程序只访问已申请的内存。这也就意味着,不会存在任何野指针。
托管代码——>中间语言(CIL)—(CLR)—>microsoft的平台专用语言,机器代码
VS编写
的源代码(不只是C#,也包括.net平台上的其他语言,如VB,J#等),首先经过编译器把代码编译成中间语言(CIL,又称IL)。
CLR在对CIL语言代码进行编译前,需要先将编译的环境运行起来并对程序集进行一个读取过程,这个读取过程其实也就描述出了程序集中的一个基本构造。
当方法被调用时,公共语言运行库CLR
把具体的方法编译成适合本地计算机运行的机器码,并且将编译好的机器码缓存起来,以备下次调用使用。
非托管代码——>机器码
运行在CLR环境外部
,直接编译成目标计算机码,由操作系统直接执行的代码,代码必须自己提供垃圾回收,类型检查,安全支持等服务。
如需要内存管理等服务,必须显示调用操作系统的接口,通常调用Windows SDK所提供的API来实现内存管理。
托管代码和非托管代码的区别:
- 托管代码运行在CLR上;非托管代码被编译为机器码,运行在机器上。
- 托管代码独立于平台和语言,能更好的实现不同语言平台之间的兼容;非托管代码依赖于平台和语言。
- 托管代码可享受CLR提供的服务(如安全检测、垃圾回收等),具有更高的安全性和可靠性;非托管代码需要自己提供安全检测、垃圾回收等操作,也更容易导致内存泄漏、悬挂指针和安全漏洞等问题。
2、C#中使用非托管代码
程序集是在 .NET 公共语言运行库 (CLR) 控制之下运行的逻辑功能单元,实际上是作为 .dll 文件或 .exe 文件存在的。
托管代码生成的程序集文件,可以在VS中直接通过添加引用的方式使用。
非托管代码生成的DLL文件,比如使用C++编写的代码编译生成的DLL,不能在VS中直接引用,可以通过DllImport等方法来使用。
DllImport
属性:
[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 {…} }
}
Dll引用路径:
(1)exe运行程序所在的目录
(2)System32目录
(3)环境变量目录
(4)自定义路径,如:DllImport(@"C:\OJ\Bin\Judge.dll")
2.1、C/C++动态库
// C/C++动态链接库中的函数
extern "C" __declspec(dllexport) int Add(int a, int b)
{
return a + b;
}
// 在C#中调用C/C++动态链接库中的函数
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("example.dll", EntryPoint = "Add")]
public static extern int C_Add(int a, int b);
static void Main()
{
int result = C_Add(5, 3);
Console.WriteLine("Result: " + result); // 输出:Result: 8
}
}
2.2、Win32 API
// 在C#中可以直接使用 Windows 提供的 Win32 API 函数
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public const int SW_HIDE = 0;
public const int SW_SHOW = 5;
static void Main()
{
IntPtr hWnd = GetConsoleWindow();
ShowWindow(hWnd, SW_HIDE); // 隐藏控制台窗口
// ShowWindow(hWnd, SW_SHOW); // 显示控制台窗口
}
}
2.3、COM 组件
COM 是一种面向对象的二进制接口标准。
// C/C++ COM组件接口
#include <windows.h>
class IMyInterface : public IUnknown
{
public:
virtual HRESULT __stdcall MyMethod() = 0;
};
class MyComponent : public IMyInterface
{
public:
// 实现MyMethod方法
HRESULT __stdcall MyMethod()
{
// 实现方法逻辑
return S_OK;
}
};
// 在C#中调用COM组件
using System;
using System.Runtime.InteropServices;
class Program
{
[ComImport]
[Guid("00000000-0000-0000-0000-000000000000")] // COM组件的GUID
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyInterface
{
void MyMethod();
}
static void Main()
{
var myComponent = (IMyInterface)new MyComponent();
myComponent.MyMethod();
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战