C# Marshal类基本概念和入门实例代码分析

发布时间:2023-02-27 09:51:16 作者:iii
来源:亿速云 阅读:193

C# Marshal类基本概念和入门实例代码分析

1. 引言

在C#编程中,我们经常需要与非托管代码进行交互,例如调用Windows API、处理COM对象或与C/C++编写的库进行通信。为了实现这些功能,C#提供了Marshal类,它是System.Runtime.InteropServices命名空间中的一个重要工具类。Marshal类提供了一系列方法,用于在托管代码和非托管代码之间进行数据转换、内存管理和类型封送(Marshaling)。

本文将详细介绍Marshal类的基本概念,并通过实例代码分析其使用方法,帮助读者更好地理解和掌握这一强大的工具。

2. Marshal类的基本概念

2.1 什么是封送(Marshaling)?

封送(Marshaling)是指在托管代码和非托管代码之间传递数据时,将数据从一种形式转换为另一种形式的过程。由于托管代码和非托管代码使用不同的内存管理方式和数据类型,因此在进行跨语言调用时,必须对数据进行适当的转换。

例如,托管代码中的string类型与非托管代码中的char*类型是不同的,因此在调用非托管函数时,需要将string转换为char*,这个过程就是封送。

2.2 Marshal类的作用

Marshal类提供了许多静态方法,用于处理托管代码和非托管代码之间的数据转换和内存管理。其主要功能包括:

2.3 常用方法介绍

Marshal类提供了许多方法,以下是一些常用的方法:

3. 实例代码分析

3.1 字符串封送

在托管代码中,字符串是System.String类型,而在非托管代码中,字符串通常是以char*wchar_t*形式表示的。我们可以使用Marshal类的方法在两者之间进行转换。

3.1.1 托管字符串转换为非托管字符串

using System;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        string managedString = "Hello, World!";
        IntPtr unmanagedString = Marshal.StringToHGlobalAnsi(managedString);

        try
        {
            // 调用非托管函数,传递unmanagedString
            Console.WriteLine("Unmanaged string: " + Marshal.PtrToStringAnsi(unmanagedString));
        }
        finally
        {
            // 释放非托管内存
            Marshal.FreeHGlobal(unmanagedString);
        }
    }
}

代码分析:

3.1.2 非托管字符串转换为托管字符串

using System;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        IntPtr unmanagedString = Marshal.StringToHGlobalAnsi("Hello, World!");

        try
        {
            string managedString = Marshal.PtrToStringAnsi(unmanagedString);
            Console.WriteLine("Managed string: " + managedString);
        }
        finally
        {
            Marshal.FreeHGlobal(unmanagedString);
        }
    }
}

代码分析:

3.2 结构体封送

在跨语言调用中,结构体的封送是一个常见的需求。Marshal类提供了StructureToPtrPtrToStructure方法,用于在托管结构体和非托管内存块之间进行转换。

3.2.1 托管结构体转换为非托管内存块

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
struct Point
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        Point point = new Point { X = 10, Y = 20 };
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(Marshal.SizeOf(point));

        try
        {
            Marshal.StructureToPtr(point, unmanagedMemory, false);

            // 调用非托管函数,传递unmanagedMemory
            Point copiedPoint = (Point)Marshal.PtrToStructure(unmanagedMemory, typeof(Point));
            Console.WriteLine($"Copied Point: X={copiedPoint.X}, Y={copiedPoint.Y}");
        }
        finally
        {
            Marshal.FreeHGlobal(unmanagedMemory);
        }
    }
}

代码分析:

3.2.2 非托管内存块转换为托管结构体

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
struct Point
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        IntPtr unmanagedMemory = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Point)));

        try
        {
            Point point = new Point { X = 10, Y = 20 };
            Marshal.StructureToPtr(point, unmanagedMemory, false);

            Point copiedPoint = (Point)Marshal.PtrToStructure(unmanagedMemory, typeof(Point));
            Console.WriteLine($"Copied Point: X={copiedPoint.X}, Y={copiedPoint.Y}");
        }
        finally
        {
            Marshal.FreeHGlobal(unmanagedMemory);
        }
    }
}

代码分析:

3.3 函数指针封送

在跨语言调用中,有时需要将托管委托转换为非托管函数指针,或者将非托管函数指针转换为托管委托。Marshal类提供了GetFunctionPointerForDelegateGetDelegateForFunctionPointer方法来实现这一功能。

3.3.1 托管委托转换为非托管函数指针

using System;
using System.Runtime.InteropServices;

class Program
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate int AddDelegate(int a, int b);

    static int Add(int a, int b)
    {
        return a + b;
    }

    static void Main()
    {
        AddDelegate addDelegate = new AddDelegate(Add);
        IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(addDelegate);

        // 调用非托管函数,传递functionPointer
        int result = ((AddDelegate)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(AddDelegate)))(3, 4);
        Console.WriteLine("Result: " + result);
    }
}

代码分析:

3.3.2 非托管函数指针转换为托管委托

using System;
using System.Runtime.InteropServices;

class Program
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate int AddDelegate(int a, int b);

    static int Add(int a, int b)
    {
        return a + b;
    }

    static void Main()
    {
        AddDelegate addDelegate = new AddDelegate(Add);
        IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(addDelegate);

        AddDelegate copiedDelegate = (AddDelegate)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(AddDelegate));
        int result = copiedDelegate(3, 4);
        Console.WriteLine("Result: " + result);
    }
}

代码分析:

4. 总结

Marshal类是C#中用于处理托管代码与非托管代码之间交互的重要工具。通过Marshal类,我们可以轻松地进行数据类型转换、内存管理、结构体封送和函数指针封送等操作。本文通过实例代码详细介绍了Marshal类的基本概念和常用方法,希望能够帮助读者更好地理解和掌握这一强大的工具。

在实际开发中,Marshal类的使用场景非常广泛,尤其是在与Windows API、COM对象或C/C++库进行交互时。掌握Marshal类的使用方法,将大大提高我们在跨语言编程中的效率和灵活性。

推荐阅读:
  1. mhdd检测不到硬盘怎么解决
  2. SQL语句知识点有哪些

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

marshal

上一篇:C#数字信号处理工具包如何使用

下一篇:C#整数如何转二进制字符串

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》