C# Marshal类基本概念和入门实例讲解
C# Marshal类是与另一个通信的进程交互的强大工具,该进程可以在同一台计算机或网络上运行。本文旨在介绍Marshal类的基本概念和学习Marshal类的入门实例。
什么是Marshal类
Marshal类是在.NET Framework中提供的一个强大的、可靠的机制,用于在C#应用程序和非托管代码(如Windows API、COM组件、动态链接库等)之间进行交互。Marshal类提供了一组方法,用于在托管代码中使用非托管代码(例如,为了访问Windows注册表信息,我们需要使用由Windows API(非托管代码)提供的功能)。
Marshal类的优点
Marshal类具有以下几个优点:
-
提供了丰富的互操作性Marshal类提供了一组方法,用于在托管代码中使用非托管代码。这些方法使得应用程序可以与其他非托管代码、操作系统和硬件组件进行通信。
-
具有更高效的内部工具Marshal类可以更高效的内部处理与非托管代码的通信,并确保如何正确地与非托管代码协作。Marshal类也可以通过向非托管代码传递指针来传递数据。
Marshal类的常用方法和示例
Marshal.PtrToStringAnsi
Marshal.PtrToStringAnsi方法将指定内存地址中的零结尾Ansi字符集字符串转换为此字符串。
下面是使用该方法转换字符串的示例代码:
public class Program
{
[DllImport("user32.dll")]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, int type);
[DllImport("Kernel32.dll")]
public static extern IntPtr LoadLibrary(string path);
[DllImport("Kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr lib, string funcName);
[DllImport("Kernel32.dll")]
public static extern bool FreeLibrary(IntPtr lib);
public static void Main(string[] args)
{
string libName = @"C:\windows\system32\user32.dll";
IntPtr lib = LoadLibrary(libName);
if(lib != IntPtr.Zero)
{
IntPtr function = GetProcAddress(lib, "MessageBoxA");
if (function != IntPtr.Zero)
{
Marshal.GetDelegateForFunctionPointer(function, typeof(MessageBoxDelegate));
}
}
else
{
Console.WriteLine("Failed to Load Library");
}
}
private delegate int MessageBoxDelegate(IntPtr hWnd, string text, string caption, int type);
}
该代码加载user32.dll库并获取API函数MessageBoxA。函数原型与系统定义不同,因为返回类型可以是int,而不是一个布尔值。为此,可以使用Marshal.GetDelegateForFunctionPointer函数,用委托类型替代IntPtr类型。
Marshal.AllocHGlobal
Marshal.AllocHGlobal 方法分配指定字节数的内存块,并返回一个表示该块的指针。
下面是使用该方法初始化内存块的示例代码:
double[] test = new double[] { 1, 2, 3, 4, 5 };
IntPtr pDoubleArray = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double)) * test.Length);
for (int i = 0; i < test.Length; i++)
{
Marshal.Copy(BitConverter.GetBytes(test[i]), 0, pDoubleArray + i * Marshal.SizeOf(typeof(double)), Marshal.SizeOf(typeof(double)));
}
该代码创建了一个包含五个双精度浮点数的数组,分配了足够大的内存以包含整个数组,并使用Marshal.Copy函数将数组元素复制到内存块。
总结
在本文中,我们学习了Marshal类的基本概念。Marhal类使得C#应用程序和非托管代码之间的交互更加简单、可靠和高效。我们还看了两个使用Marshal类的示例。Marshal.PtrToStringAnsi方法用于将指定内存地址中的零结尾Ansi字符集字符串转换为此字符串,而Marshal.AllocHGlobal方法用于分配指定字节数的内存块。