C#之P/Invoke

来源:互联网 发布:tf idf算法实现 编辑:程序博客网 时间:2024/05/03 06:25

来自:http://blog.csdn.net/yefengmeander/article/details/6989986

一、P/Invoke Instruction:

Link: An Introduction to P/Invoke and Marshaling on the Microsoft .NET Compact Framework

P/Invoke, or Pinvoke stands for Platform Invocation Services.  PInvoke is a feature of the Microsoft .NET Frameowrk that allows a developer to make calls to native code insideDynamic Link Libraries (DLL’s).  When Pinvoking, the .NET framework (or Common Language Routine) will load the DLL and handle the type conversions automatically.  The most common use of P/Invoke is to use a feature of Windows that is only contained in the Win32 API.  The API in Windows is extremely extensive and only some of the features are encapsulated in .NET libraries.  For example, Form.Show(); is really a wrapper for theShowWindow() API found in shell32.dll.

ShowWindow Declaration API for C#:

[csharp] view plaincopy
  1. <pre name="code" class="csharp">[DllImport("user32.dll")]  
  2. static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);</pre>  

Note the use of the DllImport attribute.  This attribute, coupled withextern tells the .NET CLR where it can find the native declaration for ShowWindow.  shell32.dll must be registered on the system for this to work properly.

Note: Remember import the System.Runtime.InteropServices namespace!  This is where the [DLLImport] attribute is found.

[csharp] view plaincopy
  1. <pre name="code" class="csharp">using System.Runtime.InteropServices;</pre>  

How are P/Invoked methods called?

Methods that are loaded in using DLLImport are Pinvoked by simply treating them as native .NET functions, and calling them as you would call any other.  Win32 API do tend to use data types that are not used often in .NET, for example – theIntPtr datatype, which is actually a pointer to an integer–in this case, aWindow Handle.  nCmdShow is an integer that represents the show command.  But what values of nCmdShow mean what?  These can either be found on MSDN, or PInvoke.net.

C# Constants for ShowWindow in shell32.dll:

[csharp] view plaincopy
  1. <pre name="code" class="csharp">  const int        SW_HIDE            = 0;  
  2.   const int        SW_SHOWNORMAL      = 1;  
  3.   const int        SW_NORMAL          = 1;  
  4.   const int        SW_SHOWMINIMIZED   = 2;  
  5.   const int        SW_SHOWMAXIMIZED   = 3;  
  6.   const int        SW_MAXIMIZE        = 3;  
  7.   const int        SW_SHOWNOACTIVATE  = 4;  
  8.   const int        SW_SHOW            = 5;  
  9.   const int        SW_MINIMIZE        = 6;  
  10.   const int        SW_SHOWMINNOACTIVE = 7;  
  11.   const int        SW_SHOWNA          = 8;  
  12.   const int        SW_RESTORE         = 9;  
  13.   const int        SW_SHOWDEFAULT     = 10;  
  14.   const int        SW_FORCEMINIMIZE   = 11;  
  15.   const int        SW_MAX             = 11;<span style="color:#008000;"></span></pre>  

These constants can be used to call ShowWindow().  So in our origional example ofForm.Show(), the P/Invoked way of doing this would be:

[csharp] view plaincopy
  1. <pre name="code" class="csharp">ShowWindow(Form.Handle, SW_SHOW);</pre>  

This isn’t nearly as clean as the Object-Oriented way of using Form.Show(), but this is what is actually happening under the hood of .NET.

Why would I ever want something so overly complicated?

ShowWindow is an example of an API that has been wrapped nicely by the .NET CLR, it is unlikely that you will ever need to import and call it.  But something more useful might be:Deleting a file to the recycle bin.

What resources are out there for PInvoking?

The best resource I have found is PInvoke.net, which has declarations for both VB.NET and C# for commonly used Win32 API.


二、P/Invoke Tool:

Use P/Invoke Interop Assistant Tool automatic generator C# signature for P/Invoke call Windows API

在.NET程序中调用Win32 API,或者调用自己的VC DLL里面提供的函数的时候,总是被生成正确的C函数在C#中的正确声明而困扰,而生成C++中结构体在C#中的声明 - 天,没有什么比这个更让人恶心的事情了。因为:C

1.         如果你的结构体里面包含 TCHAR字符串成员的话,需要考虑ANSI和Unicode DLL的情形。

2.         如果你的结构体里面包含数组成员,需要考虑定长的数组,而不是对应C#数据类型。

3.         如果你的结构体里面包含联合体(UNION),需要使用Explict选项,如果联合体里面又包含结构体。

4.         你还要考虑你的结构体可以同时在32位和64位机上运行。

5.         你还要考虑C编译器对结构体所作的PADDING的优化。

6.         你还要考虑在.NET里面对结构体的优化,例如CLR会将一些.NET struct的成员的次序变换—以便更有效地利用内存。

7.         如果你的结构里面还包含了其他的结构体。

8.         如果你的结构体里面还包含函数指针……

9.         如果你的结构体里面包含函数指针数组。

10.     如果你的结构体里面包含了指针……

11.     如果你的结构体里面有一些成员是被所调用的C函数所设置的。

12.     CLR提供了几种结构体的布局选项,什么Auto,什么Explicit,什么Sequential

13.     有的结构体的情况是上面说的情形的综合,想想我们的VARIANT结构吧。

 

如果结构体定义错误的话,在使用的时候,CLR只是简简单单地抛出一个AccessViolationException,真是叫天天不应,叫地地不灵。

另外还有一种情形就是在C中定义.NET的结构体对应的声明,这样C或者C++程序可以使用这个结构,调用.NET的类库提供的一些函数,这个转换也是一个痛苦的过程。

微软自己也是深受.NET蹩脚的P/Invoke支持的毒害,因此无奈之余发布了P/Invoke Interop Assistant工具,你可以去下面这个链接来下载这个工具:

http://download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/CLRInsideOut2008_01.exe

 这个工具已经开源,可以从这里下载到它的源代码。

http://www.codeplex.com/clrinterop/


简单介绍一下它的用法

自动生成Native函数或者结构在.NET程序中的声明,切换到“SigImp Translate Snippet”标签,然后将Native函数或者结构的声明拷贝到“Native Code Snippet”文本框里面,然后选中“Auto Generate”对话框,点击“Generate”就可以获取对应的.NET声明,如下图所示:

 

查找Win32 API中在.NET中的声明,选择“SigImp Search”,并在“Name”文本框里面输入你要查找的函数或者结构名称就可以了,如下图所示:

 

验证或者生成.NET函数(或结构)在C 中的声明,切换到“SigExp”并且打开一个包含P/Invoke函数调用的.NET Assembly就可以了,这个程序会显示对应的C的声明,并且告诉你C#声明编写错误的地方:


原创粉丝点击