日期:2011-05-30  浏览次数:20542 次

这是三篇网上收集的技术文章的合集,分别讲解了如何创建Win32 DLL,然后如何在C#里面调用这个DLL的教程。

首先是创建Win32 DLL的文章。讲解这个的文章到处都有,这里给出一篇我看过的:http://www.flipcode.com/articles/article_creatingdlls.shtml。Win32 DLL的创建其实在Visual Studio里面已经给出了比较好的模板,只是需要注意的,有些XXX_API宏并没有把extern "C"加进去,这样会造成在C#里面找不到这个函数的错误。所以,请记住,一定要把函数定义extern "C"。


第二篇文章来之于http://edu.100down.com/it/program/Csharp/105256797.html,下面是转贴内容:

平台调用服务 (PInvoke) 允许托管代码调用在 DLL 中实现的非托管函数。

本教程说明使用什么方法才能从 C# 调用非托管 DLL 函数。该教程所讨论的属性允许您调用这些函数并使数据类型得到正确封送。

教程

C# 代码有以下两种可以直接调用非托管代码的方法:

  • 直接调用从 DLL 导出的函数。
  • 调用 COM 对象上的接口方法(有关更多信息,请参见 COM Interop 第一部分:C# 客户端教程)。

对于这两种技术,都必须向 C# 编译器提供非托管函数的声明,并且还可能需要向 C# 编译器提供如何封送与非托管代码之间传递的参数和返回值的说明。

该教程由下列主题组成:

  • 直接从 C# 调用 DLL 导出
  • 默认封送处理和为非托管方法的参数指定自定义封送处理
  • 为用户定义的结构指定自定义封送处理
  • 注册回调方法

该教程包括下列示例:

  • 示例 1 使用 DllImport
  • 示例 2 重写默认封送处理
  • 示例 3 指定自定义封送处理

直接从 C# 调用 DLL 导出

若要声明一个方法使其具有来自 DLL 导出的实现,请执行下列操作:

  • 使用 C# 关键字 staticextern 声明方法。
  • DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的 DLL 的名称。通常的做法是用与导出的方法相同的名称命名 C# 方法,但也可以对 C# 方法使用不同的名称。
  • 还可以为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET Framework 的默认封送处理。

示例 1

本示例显示如何使用 DllImport 属性通过调用 msvcrt.dll 中的 puts 输出消息。

// PInvokeTest.csusing System;using System.Runtime.InteropServices;class PlatformInvokeTest{    [DllImport("msvcrt.dll")]    public static extern int puts(string c);    [DllImport("msvcrt.dll")]    internal static extern int _flushall();    public static void Main()     {        puts("Test");        _flushall();    }}

输出

Test

代码讨论

前面的示例显示了声明在非托管 DLL 中实现的 C# 方法的最低要求。PlatformInvokeTest.puts 方法用 staticextern 修饰符声明并且具有 DllImport 属性,该属性使用默认名称 puts 通知编译器此实现来自 msvcrt.dll。若要对 C# 方法使用不同的名称(如 putstring),则必须在 DllImport 属性中使用 EntryPoint 选项,如下所示:

[DllImport("msvcrt.dll", EntryPoint="puts")]

有关 DllImport 属性的语法的更多信息,请参见 DllImportAttribute 类。

默认封送处理和为非托管方法的参数指定自定义封送处理

当从 C# 代码中调用非托管函数时,公共语言运行库必须封送参数和返回值。

对于每个 .NET Framework 类型均有一个默认非托管类型,公共语言运行库将使用此非托管类型在托管到非托管的函数调用中封送数据。例如,C# 字符串值的默认封送处理是封送为 LPTSTR(指向 TCHAR 字符缓冲区的指针)类型。可以在非托管函数的 C# 声明中使用 MarshalAs 属性重写默认封送处理。

示例 2

本示例使用 DllImport 属性输出一个字符串。它还显示如何通过使用 MarshalAs 属性重写函数参数的默认封送处理。

// Marshal.csusing System;using System.Runtime.InteropServices;class PlatformInvokeTest{    [DllImport("msvcrt.dll")]    public static extern int puts(        [MarshalAs(UnmanagedType.LPStr)]        string m);    [DllImport("msvcrt.dll")]    internal static extern int _flushall();    public static void Main()     {        puts("Hello World!");        _flushall();    }}

输出

运行此示例时,字符串

Hello World!

将显示在控制台上。

代码讨论

在前面的示例中,puts 函数的参数的默认封送处理已从默认值 LPTSTR 重写为 LPSTR。

MarshalAs 属性可以放置在方法参数、方法返回值以及结构和类的字段上。若要设置方法返回值的封送处理,请将 MarshalAs 属性与返回属性位置重写一起放置在方法上的属性块中。例如,若要显式设置 puts 方法返回值的封送处理:

...[DllImport("msvcrt.dll")] [return : MarshalAs(UnmanagedType.I