C#调用非受管DLL:方法与示例

0 下载量 136 浏览量 更新于2024-08-29 收藏 94KB PDF 举报
"从C#程序中调用非受管DLLs的方法" 在.NET框架中,C#是一种现代的、面向对象的编程语言,它通常与受管代码(managed code)一起工作,这意味着代码运行在.NET运行时环境中。然而,有时我们需要调用那些非受管的DLL,比如Win32 API,这些API通常是用C或C++编写的,不直接支持.NET框架。本文主要探讨如何在C#程序中调用这样的非受管DLL函数。 首先,调用非受管DLL的关键在于使用`DllImport`特性。这个特性允许C#代码声明一个函数,该函数的实现是在非受管的DLL中。例如,以下代码展示了如何声明`SetWindowText`函数,这个函数来自`User32.dll`: ```csharp using System.Runtime.InteropServices; public class Win32 { [DllImport("User32.dll")] public static extern void SetWindowText(int hWnd, string text); } ``` 在这个例子中,`DllImport`特性告诉C#编译器该函数在哪个DLL中,而`extern`关键字表示函数的实现是在外部。函数的参数类型需要正确匹配非受管DLL中的原型,这里`int`代表窗口句柄(HWND),`string`代表文本。 处理非受管DLL的挑战之一是类型转换,因为C#和非受管代码中的数据类型可能不同。例如,C#中的字符串和非受管代码中的`char*`类型就需要特别处理。对于`char*`类型的输出参数,可以使用`StringBuilder`类来接收返回的字符串。`StringBuilder`提供了对内存缓冲区的控制,适合接收动态增长的字符串。 对于包含结构(struct)和回调(callback)参数的函数,如`GetWindowsRect`和`EnumWindows`,需要更复杂的处理。结构通常需要使用`[StructLayout]`和`[FieldOffset]`特性来指定内存布局,确保它们与非受管代码的结构匹配。回调函数则需要定义一个委托类型,并在`DllImport`中指定其为回调函数。例如: ```csharp [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); public class Win32 { [DllImport("User32.dll")] public static extern bool EnumWindows(EnumWindowsProc callback, IntPtr userData); } ``` 在上面的例子中,`EnumWindowsProc`是一个委托,它定义了回调函数的签名,`EnumWindows`函数接受这个委托作为参数。 除了基本的数据类型转换,还需要考虑内存管理。非受管代码可能期望程序员手动管理内存,而在.NET中,这是由垃圾收集器自动处理的。因此,调用非受管代码时可能需要使用`GCHandle`来创建对对象的引用,防止垃圾收集器过早回收。 总结来说,从C#中调用非受管DLL涉及的主要知识点包括: 1. 使用`DllImport`特性声明非受管函数。 2. 正确匹配函数的参数类型,包括`char*`、结构和回调函数。 3. 使用`StringBuilder`处理返回的字符串。 4. 定义委托类型来处理回调函数。 5. 理解和处理非受管代码中的内存管理。 通过熟练掌握这些知识点,C#程序员就能充分利用.NET环境的同时,灵活地调用非受管DLL中的功能,从而实现与旧代码的集成或者利用特定的系统功能。