无痕客

落花无情,流水无痕……

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

  我在学习研究WorldWind的源代码时,发现它的底层代码大量调用外部的dll,包括不同平台的DLL。也就是托管语言C#中调用非托管的dll函数。以前也遇到了这样的情况,自己只是“依猫画虎”并没深入学习和了解。现在我分几部分学习,算是弥补这一不足! 

  Interop的意思就是托管/非托管代码之间的互操作。   

 

  extern 修饰符用于声明在外部实现的方法。extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 属性一起使用在这种情况下,该方法还必须声明为 static,如下面的示例所示:

  [DllImport("avifil32.dll")]
  private static extern void AVIFileInit();

  将 abstract和 extern 修饰符一起使用来修改同一成员是错误的。使用 extern 修饰符意味着方法在 C# 代码的外部实现,而使用 abstract 修饰符意味着在类中未提供方法实现。

      示例:

在该示例中,程序接收来自用户的字符串并将该字符串显示在消息框中。程序使用从 User32.dll 库导入的 MessageBox 方法。

using System;
using System.Runtime.InteropServices;
class MainClass
{
   [DllImport("User32.dll")]
   public static extern int MessageBox(int h, string m, string c, int type);

   static int Main()
   {
      string myString;
      Console.Write("Enter your message: ");
      myString = Console.ReadLine();
      return MessageBox(0, myString, "My Message Box", 0);
   }
}
 
 
  DllImportAttribute 类:

  指示该属性化方法由非托管动态链接库 (DLL) 作为静态入口点公开。用 DllImport 属性修饰的方法必须具有static  extern 修饰符。

  命名空间:System.Runtime.InteropServices

  DllImportAttribute 属性提供对从非托管 DLL 导出的函数进行调用所必需的信息。作为最低要求,必须提供包含入口点的 DLL 的名称。可直接将此属性应用于 C# 或 C++ 方法定义;

注意 JScript 不支持此属性。可以使用 C# 或 Visual Basic 包装类从 JScript 程序访问非托管 API 方法。

    示例

下面的代码示例演示如何使用 DllImportAttribute 属性导入 Win32 MessageBox 函数。然后,代码示例将调用导入的方法。

using System;
using System.Runtime.InteropServices;

class Example
{
    // Use DllImport to import the Win32 MessageBox function.
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
    
    static void Main()
    {
        // Call the MessageBox function using platform invoke.
        MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
    }
}

    

  使用非托管 DLL 函数:http://msdn.microsoft.com/zh-cn/library/26thfadc(VS.80).aspx

  利用平台调用这种服务,托管代码可以调用在动态链接库 (DLL)(如 Win32 API 中的 DLL)中实现的非托管函数。此服务将查找并调用导出的函数,然后根据需要跨越互用边界封送其参数(整数、字符串、数组、结构等)。

      使用导出的 DLL 函数

  1. 标识 DLL 中的函数

    最低限度上,必须指定函数的名称和包含该函数的 DLL 的名称。

  2. 创建用于容纳 DLL 函数的类

    可以使用现有类,为每一非托管函数创建单独的类,或者创建包含一组相关的非托管函数的一个类。

  3. 在托管代码中创建原型

    [Visual Basic] 使用带 FunctionLib 关键字的 Declare 语句。在某些少见的情况下,可以使用带 Shared Function 关键字的 DllImportAttribute。这些情况在本节后面部分进行说明。

    [C#] 使用 DllImportAttribute 标识 DLL 和函数。用 staticextern 修饰符标记方法。

    [C++] 使用 DllImportAttribute 标识 DLL 和函数。用 extern "C" 标记包装方法或函数。

  4. 调用 DLL 函数

    像处理其他任何托管方法一样调用托管类上的方法。传递结构实现回调函数属于特殊情况。  

  利用平台调用,可以通过调用 Win32 API 和其他 DLL 中的函数来控制操作系统中相当大的一部分。除了 Win32 API 之外,还有许多其他的 API 和 DLL 可通过平台调用来调用。

下表将说明 Win32 API 中几个常用的 DLL。

DLL 内容说明

GDI32.dll

用于设备输出的图形设备接口 (GDI) 函数,例如用于绘图和字体管理的函数。

Kernel32.dll

用于内存管理和资源处理的低级别操作系统函数。

User32.dll

用于消息处理、计时器、菜单和通信的 Windows 管理函数。

 

         

下面的示例将说明如何定义和调用 User32.dll 中的 MessageBox 函数,并将简单字符串当作参数进行传递。在这些示例中,DllImportAttribute.CharSet Field 字段设置为 Auto,以便让目标平台确定字符宽度和字符串封送处理。

C#

using System.Runtime.InteropServices;

public class Win32 {
     [DllImport("user32.dll", CharSet=CharSet.Auto)]
     public static extern IntPtr MessageBox(int hWnd, String text, 
                     String caption, uint type);
}

public class HelloWorld {
    public static void Main() {
       Win32.MessageBox(0, "Hello World", "Platform Invoke Sample", 0);
    }
}      
C++
using namespace System::Runtime::InteropServices;

typedef void* HWND;
[DllImport("user32", CharSet=CharSet::Auto)]
extern "C" IntPtr MessageBox(HWND hWnd,
                          String* pText,
                          String* pCaption,
                          unsigned int uType);
void main(void) {
     String* pText = L"Hello World!";
     String* pCaption = L"Platform Invoke Sample";
     MessageBox(0, pText, pCaption, 0);
}


 

 

posted on 2009-12-09 21:16  无痕客  阅读(3397)  评论(1编辑  收藏  举报