托管与非托管

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把具体的方法编译成适合本地计算机运行的机器码,并且将编译好的机器码缓存起来,以备下次调用使用。

非托管代码——>机器码

运行在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();
    }
}
posted @ 2024-03-29 16:54  茜茜87  阅读(3)  评论(0编辑  收藏  举报