现在的位置: 首页 > 综合 > 正文

C# P/Invoke

2013年09月30日 ⁄ 综合 ⁄ 共 4369字 ⁄ 字号 评论关闭

P/Invoke什么意思? Platform Invocation Services

应用?  导入不属于.Net托管的外部函数。

P/Invoke 是使托管代码调用DLL中实现的非托管函数的服务。比如Win32的API、COM,自定义的C API等,并能定位和调用导出的函数,跨越交互边界marshal它们的参数。
Managed   Code  -> Complier-> CLR-> P/Invoke-> Marchalling-> UnManaged   DLL   Function。

charset如何使用?****A的是Ansi编码,****W的是unicode编码,如何使用charset,看你的函数调用而定。2K以后都用unicode了,前面的9x都是ansi编码,但是这是缺省的,微软给9x打布丁支持unicode不算。

API有两个版本: A(ASNI)版本和W(Unicode)版本. A版本调用时候会用ANSI来封送字符串,一般是win95/98上。W版本用Unicode来封送,在NT,2K和XP上。.Net和win32交互的时候,默认是使用CharSet.Ansi来传送。

在 DllImportAttribute.ExactSpelling 字段为 true 时(它是 Visual Basic .NET 中的默认值),平台调用将只搜索您指定的名称。例如,如果指定 MessageBox,则平台调用将搜索 MessageBox,如果它找不到完全相同的拼写则失败。

当 ExactSpelling 字段为 false(它是 C++ 托管扩展和 C# 中的默认值),平台调用将首先搜索未处理的别名 (MessageBox),如果没有找到未处理的别名,则将搜索已处理的名称 (MessageBoxA/MessageBoxW)。请注意,ANSI 名称匹配行为与 Unicode 名称匹配行为不同。

         //CharSet.Ansi will call MessageBoxA
         //CharSet.Unicode will call MessageBoxW
         [DllImport("user32.dll",EntryPoint="MessageBox",CharSet=CharSet.Ansi)]
         static extern int MyMsg(int hWnd,
                                          string msg,
                                          string caption,
                                          int type );

         private void button1_Click(object sender, System.EventArgs e)
         {
              MyMsg( 0, "Msg:hello", "Caption:Hello",0 );
         }

Dll里面的callback函数如何实现?

看下面这个例子:

       delegate bool CallBackDef( int hWnd, int lParm );
         [DllImport("user32.dll")]
              static extern int GetWindowText( int hWnd,
                                                   StringBuilder text,
                                                   int count );

         [DllImport("user32.dll")]
              static extern int EnumWindows(CallBackDef callback, int lParam );

         static bool PrintWindow(int hWnd, int lParm )
         {
              StringBuilder text = new StringBuilder(255);
              GetWindowText( hWnd, text, 255 );
              Console.WriteLine( text.ToString() );
              return true;
         }

         private void button1_Click(object sender, System.EventArgs e)
         {
              CallBackDef callBack = new CallBackDef( PrintWindow );
              EnumWindows( callBack, 0 );
         }

MarshalAs如何用,什么时候用
在MessageBox传递string去Dll的时,C#编译器知道Win32 LPSTR等价与一个C#字符串。但是如果想覆盖默认.Net行为, 这时候就需要MarshallAs
[DllImport("user32.dll", CharSet=CharSet.Unicode )]
              static extern int MessageBox( int hWnd,
                                               [MarshalAs(UnmanagedType.LPWStr)]
                                               string msg,
                                               [MarshalAs(UnmanagedType.LPWStr)]
                                               string caption,
                                               int type);

我怎么知道要调用的函数在那个dll
这个问题我不会比你更清楚,特殊的函数应该在你特殊的dll中。Win32中常用的几个dll是user32.dll, kernel32.dll和GDI32.dll。用dumpbin -exports kernel32.dll可以看到这个dll所有的API函数。

相互之间传递struct怎么办

传递一个结构,这个要用到StructLayoutAttribute属性。比如:

PtInRect 具有以下非托管签名:
BOOL PtInRect(const RECT *lprc, POINT pt);

请注意,由于函数需要指向 RECT 类型的指针,必须通过引用来传递 Rect 结构。
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct Point
{
     public int x;
     public int y;
}   

[StructLayout(LayoutKind.Explicit)]
public struct Rect
{
     [FieldOffset(0)] public int left;
     [FieldOffset(4)] public int top;
     [FieldOffset(8)] public int right;
     [FieldOffset(12)] public int bottom;
}   

class Win32API
{
     [DllImport("User32.dll")]
     public static extern bool PtInRect(ref Rect r, Point p);
}

哪里有不错的教程

google一下多的是。MSDN里面也有一些不错的教程:(vs.net 2003)

平台调用数据类型
提供托管数据类型及其相应的非托管数据类型的列表。
封送字符串
描述如何通过值、通过引用、在结构中、在类中和在数组中传递字符串。
封送类、结构和联合
描述如何通过值传递类,如何传递各种结构以及如何传递具有值和混合类型的联合。
封送类型数组
描述如何通过值传递多维整数数组以及如何通过引用传递一维数组。
其他封送处理示例
描述影响 Interop 封送处理行为的垃圾回收和线程处理的各个方面。

最后,这位大哥,你说了很多,我想问一个对我来说最关键的问题,我看了你的东西,似是而非,不会用怎么办?这里有一个PInvoke的Add-In tools for Visual Studio.Net,几乎所有的Win32 API都有。安装了以后,基本不用自己写了。
http://www.pinvoke.net

更多链接:

•MSDN Magazine
◦2003年7月刊.NET专栏:Calling Win32 DLLs in C# with P/Invoke by Jason Clark
◦2004年10月刊.NET专栏:P/Invoke Revisited by Jason Clark
•MSDN
◦Microsoft Win32 to Microsoft .NET Framework API Map ,Win32 API的很多功能已经在.NET中实现了,这篇文章列出了对应关系。
◦An Overview of Managed/Unmanaged Code Interoperability ,P/Invoke服务其实只是托管代码和非托管代码之间进行交互操作中的一个功能而已,本文对Interop做了一个概述。

•其他文章
◦Using P/Invoke to Access Win32 APIs
◦在C#中使用P/Invoke调用Win32 DLL,译文,原文Calling Win32 DLLs in C# with P/Invoke
◦如何在C#中使用Win32和其他库,仍然是译文,但没找到原文
◦在 C# 中通过 P/Invoke 调用Win32 DLL,另一个网友的译文,原文还是Calling Win32 DLLs in C# with P/Invoke
◦P/Invoke使用Win32非托管函数

◦.NET/C# 2.0对于P/Invoke支持的几处增强

•P/Invoke网站
◦PInvoke.net:the interop wiki,在这里可以找到Win32 API函数的原型,以及使用C#调用的示例。
◦N/Direct - The .NET Interoperability Resource Center

抱歉!评论已关闭.