天天看点

从C#程序中调用非受管DLLs [择自博客园]

众所周知,.NET已经渐渐成为一种技术时尚,那么C#很自然也成为一种编程时尚。如何利用浩如烟海的Win32 API以及以前所编写的 Win32 代码已经成为越来越多的C#程序员所关注的问题。本文将介绍如何从C#代码中调用非受管DLLs。如果某个函数是一个带有串类型(char*)输出参数的Win32 API 或者是DLL输出函数,那么从C#中如何调用它呢?对于输入参数的情形问题到不大,但如何获取从参数中返回的串呢?此外,如何调用有结构(struct)和回调(callback)作为参数的函数,如GetWindowsRect 和EnumWindows?那我们又如何将参数从C++和MFC中转换成C# 所要的类型呢?下面就让我们来一一解决这些问题。

    微软.NET的一个最主要的优势是它提供一个语言无关的开发系统。我们可以用Visual Basic、C++、C#等等语言来编写类,然后在其它语言中使用,我们甚至可以用不同的语言来派生类。但是如何调用以前开发的非受管DLL呢?方法是必须将.NET对象转化成结构、char*以及C语言的指针。用行话说就是参数必须被列集(marshal)。说到列集,用一两句话也说不清楚。所幸的是实现列集并不要我们知道太多的东西。

    为了从C# 中调用DLL函数,首先必须要有一个声明,就象长期以来使用Visual Basic的程序员所做的那样,只不过在C#中使用的是DllImport关键字: 

从C#程序中调用非受管DLLs [择自博客园]

  using  System.Runtime.InteropServices;  //  DllImport所在的名字空间

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

public   class  Win32 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

  [DllImport("User32.Dll")]

从C#程序中调用非受管DLLs [择自博客园]

  public static extern void SetWindowText(int h, String s);

从C#程序中调用非受管DLLs [择自博客园]

}

    在C#中,DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在一个类中。我们可以为这类取任何名字,这里不妨将类名取为 Win32。我们甚至可以将这个类放到一个名字空间中,就象下面的代码这样: ///

Win32API.cs 源代码

从C#程序中调用非受管DLLs [择自博客园]

//  Win32API: 此为名字空间,打包所选的Win32 API 函数

从C#程序中调用非受管DLLs [择自博客园]

//  编译方法:

从C#程序中调用非受管DLLs [择自博客园]

//     csc /t:library /out:Win32API.dll Win32API.cs

从C#程序中调用非受管DLLs [择自博客园]

//

从C#程序中调用非受管DLLs [择自博客园]

using  System;

从C#程序中调用非受管DLLs [择自博客园]

using  System.Drawing;

从C#程序中调用非受管DLLs [择自博客园]

using  System.Text;

从C#程序中调用非受管DLLs [择自博客园]

using  System.Runtime.InteropServices;

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

/////

从C#程序中调用非受管DLLs [择自博客园]

//  包装Win32 API函数的名字空间。想用哪个Win32 API,往里添加即可。

从C#程序中调用非受管DLLs [择自博客园]

//

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

namespace  Win32API 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

   [StructLayout(LayoutKind.Sequential)]

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   public struct POINT 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public POINT(int xx, int yy) 

从C#程序中调用非受管DLLs [择自博客园]

{ x=xx; y=yy; }

从C#程序中调用非受管DLLs [择自博客园]

      public int x;

从C#程序中调用非受管DLLs [择自博客园]

      public int y;

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public override string ToString() 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

         String s = String.Format("({0},{1})", x, y);

从C#程序中调用非受管DLLs [择自博客园]

         return s;

从C#程序中调用非受管DLLs [择自博客园]

      }

从C#程序中调用非受管DLLs [择自博客园]

   }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   [StructLayout(LayoutKind.Sequential)]

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   public struct SIZE 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public SIZE(int cxx, int cyy) 

从C#程序中调用非受管DLLs [择自博客园]

{ cx=cxx; cy=cyy; }

从C#程序中调用非受管DLLs [择自博客园]

      public int cx;

从C#程序中调用非受管DLLs [择自博客园]

      public int cy;

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public override string ToString() 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

         String s = String.Format("({0},{1})", cx, cy);

从C#程序中调用非受管DLLs [择自博客园]

         return s;

从C#程序中调用非受管DLLs [择自博客园]

      }

从C#程序中调用非受管DLLs [择自博客园]

   }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   [StructLayout(LayoutKind.Sequential)]

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   public struct RECT 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

      public int left;

从C#程序中调用非受管DLLs [择自博客园]

      public int top;

从C#程序中调用非受管DLLs [择自博客园]

      public int right;

从C#程序中调用非受管DLLs [择自博客园]

      public int bottom;

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public int Width()      

从C#程序中调用非受管DLLs [择自博客园]

{ return right - left; }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public int Height()     

从C#程序中调用非受管DLLs [择自博客园]

{ return bottom - top; }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public POINT TopLeft()  

从C#程序中调用非受管DLLs [择自博客园]

{ return new POINT(left,top); }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public SIZE  Size()     

从C#程序中调用非受管DLLs [择自博客园]

{ return new SIZE(Width(), Height()); }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public override string ToString() 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

         String s = String.Format("{0}x{1}", TopLeft(), Size());

从C#程序中调用非受管DLLs [择自博客园]

         return s;

从C#程序中调用非受管DLLs [择自博客园]

      }

从C#程序中调用非受管DLLs [择自博客园]

   }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   public class Win32 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

      public static extern bool IsWindowVisible(int hwnd);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

      public static extern int GetWindowText(int hwnd,

从C#程序中调用非受管DLLs [择自博客园]

         StringBuilder buf, int nMaxCount);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

      public static extern int GetClassName(int hwnd,

从C#程序中调用非受管DLLs [择自博客园]

         [MarshalAs(UnmanagedType.LPStr)] StringBuilder buf,

从C#程序中调用非受管DLLs [择自博客园]

         int nMaxCount);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

      public static extern int GetWindowRect(int hwnd, ref RECT rc);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

      // 注意,运行时知道如何列集一个矩形

从C#程序中调用非受管DLLs [择自博客园]

      public static extern int GetWindowRect(int hwnd, ref Rectangle rc);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   }

从C#程序中调用非受管DLLs [择自博客园]

}       

从C#程序中调用非受管DLLs [择自博客园]

用下面的命令行可以编译这段代码: csc /t:library /out:Win32API.dll Win32API.cs     

成功编译后,我们就有了一个可以在C#工程中使用的动态库了(Win32API.dll)。 

从C#程序中调用非受管DLLs [择自博客园]

using  Win32API;

从C#程序中调用非受管DLLs [择自博客园]

int  hwnd  =   //  get it

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

String s  =   " I''''m so cute. "  ;

从C#程序中调用非受管DLLs [择自博客园]

Win32.SetWindowText(hwnd, s);    

编译器知道在user32.dll中找到SetWindowText,并在调用前自动将串转换为LPTSTR (TCHAR*)。真是神奇!.NET是如何实现的呢?其实,每一个C#类型都有一个缺省的列集类型。对于串来说,它的列集类型就是LPTSTR。但如果调用的是GetWindowText,它的串参数是一个输出参数,而非输入参数,因为串是不变的,再象上面这样处理就行不通了。我们可能一点都没有注意到,不论什么时候处理一个串时,都会创建一个新串。要想修改这个串,必须用StringBuilder: using System.Text; // StringBuilder所在的名字空间

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

public   class  Win32 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

  [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

  public static extern int GetWindowText(int hwnd,

从C#程序中调用非受管DLLs [择自博客园]

    StringBuilder buf, int nMaxCount);

从C#程序中调用非受管DLLs [择自博客园]

}

StringBuilder缺省的列集类型是LPTSTR,但是GetWindowText现在可以修改实际的串。

从C#程序中调用非受管DLLs [择自博客园]

int  hwnd  =   //  get it

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

StringBuilder sb  =   new  StringBuilder( 256 );

从C#程序中调用非受管DLLs [择自博客园]

Win32.GetWindowText(hwnd, sb, sb.Capacity);     

从C#程序中调用非受管DLLs [择自博客园]

所以我们第一个问题的答案就是:使用StringBuilder。 前面讨论的方法固然可以行得通,但有一种情况没有考虑,那就是如果缺省的列集类型不是你想要的类型怎么办?例如想要调用GetClassName,Windows编程高手都知道,GetClassName的参数与大多数其它的API函数的参数有所不同,它的串参数是LPSTR (char*),甚至是Unicode串。如果传递一个串,公共语言运行时(CLR)将把它转换成TCHARs——是不是很糟啊!不用害怕,我们可以用MarshalAs来改写缺省的处理:

从C#程序中调用非受管DLLs [择自博客园]

[DllImport( " user32.dll " )]

从C#程序中调用非受管DLLs [择自博客园]

public   static   extern   int  GetClassName( int  hwnd,

从C#程序中调用非受管DLLs [择自博客园]

  [MarshalAs(UnmanagedType.LPStr)] StringBuilder buf,

从C#程序中调用非受管DLLs [择自博客园]

   int  nMaxCount);      

从C#程序中调用非受管DLLs [择自博客园]

    现在我们调用GetClassName,.NET将串作为ANSI字符传递,而不是宽字符,搞掂! 以上我们解决了如何获取函数载参数中返回的字符串。下面我们来看看结构参数和回调参数的情形。不用说,.NET肯定有办法处理它们。就拿GetWindowRect为例。这个函数用窗口屏幕坐标填充一个RECT。 // 在C/C++中

RECT rc;

HWND hwnd = FindWindow("foo",NULL);

::GetWindowRect(hwnd, &rc);      

在C#中如何调用呢?如何传递RECT呢?方法是将它作为一个C#结构,用另一个属性:它就是StructLayout: 

从C#程序中调用非受管DLLs [择自博客园]

[StructLayout(LayoutKind.Sequential)]

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

public   struct  RECT 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

  public int left;

从C#程序中调用非受管DLLs [择自博客园]

  public int top;

从C#程序中调用非受管DLLs [择自博客园]

  public int right;

从C#程序中调用非受管DLLs [择自博客园]

  public int bottom;

从C#程序中调用非受管DLLs [择自博客园]

}      

一旦有了结构定义,便可以象下面这样来打包实现: [DllImport("user32.dll")]

从C#程序中调用非受管DLLs [择自博客园]

public   static   extern   int  

从C#程序中调用非受管DLLs [择自博客园]

  GetWindowRect( int  hwnd,  ref  RECT rc);    

注意这里用到了ref,这一点很重要,CLR会将RECT作为引用传递,以便函数可以修改我们的对象,而不是无名字的堆栈拷贝。定义了GetWindowRect之后,我们可以象下面这样调用:

从C#程序中调用非受管DLLs [择自博客园]

RECT rc  =   new  RECT();

从C#程序中调用非受管DLLs [择自博客园]

int  hwnd  =   //  get it 

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

Win32.GetWindowRect(hwnd,  ref  rc);      

注意这里必须声明并使用ref——罗嗦!C# 结构的缺省列集类型还能是什么?——LPStruct,所以就不必再用MarshalAs了。但如果RECT是个类,而非结构的话,那就必须象下面这样实现打包:

从C#程序中调用非受管DLLs [择自博客园]

//  如果RECT 是个类,而不是结构

从C#程序中调用非受管DLLs [择自博客园]

[DllImport( " user32.dll " )]

从C#程序中调用非受管DLLs [择自博客园]

public   static   extern   int  

从C#程序中调用非受管DLLs [择自博客园]

  GetWindowRect( int  hwnd, 

从C#程序中调用非受管DLLs [择自博客园]

    [MarshalAs(UnmanagedType.LPStruct)] RECT rc);      

从C#程序中调用非受管DLLs [择自博客园]

C#与C++类似,许多事情都可以殊途同归,System.Drawing中已经有了一个Rectangle结构用来处理矩形,所以为什么要重新发明轮子呢?

从C#程序中调用非受管DLLs [择自博客园]

[DllImport( " user32.dll " )]

从C#程序中调用非受管DLLs [择自博客园]

public   static   extern   int  GetWindowRect( int  hwnd,  ref  Rectangle rc);      

从C#程序中调用非受管DLLs [择自博客园]

运行时既然已经知道如何将Rectangle作为Win32 RECT进行列集。请注意,在实际的代码中就没有必要再调用GetWindowRect(Get/SetWindowText亦然),因为Windows.Forms.Control类已具有这样的属性:用Control.DisplayRectangle获取窗口矩形,用Control.Text设置/获取控件文本 

从C#程序中调用非受管DLLs [择自博客园]

Rectangle r  =  mywnd.DisplayRectangle;

从C#程序中调用非受管DLLs [择自博客园]

mywnd.Text  =   " I''''m so cute " ;       

如果出于某种原因已知的是某个HWND,而不是一个控件派生对象,那么只需要象示范的那样来打包API。以上我们已经搞掂了串、结构以及矩形……还有什么呢?对了,还有回调(callbacks)。如何将回调从C#传递到非受管代码呢?记住只要用委托(delegate)即可: delegate bool EnumWindowsCB(int hwnd,     int lparam);      

一旦声明了委托/回调类型,就可以象下面这样打包: 

从C#程序中调用非受管DLLs [择自博客园]

[DllImport( " user32 " )]

从C#程序中调用非受管DLLs [择自博客园]

public   static   extern   int  

从C#程序中调用非受管DLLs [择自博客园]

  EnumWindows(EnumWindowsCB cb,  int  lparam);    

从C#程序中调用非受管DLLs [择自博客园]

上面的delegate仅仅是声明了一个委托类型,我们还必须在类中提供一个实际的委托实现: 

从C#程序中调用非受管DLLs [择自博客园]

//  在类中

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

public   static   bool  MyEWP( int  hwnd,  int  lparam) 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

  // do something

从C#程序中调用非受管DLLs [择自博客园]

  return true;

从C#程序中调用非受管DLLs [择自博客园]

}      

然后对它进行打包处理: 

从C#程序中调用非受管DLLs [择自博客园]

EnumWindowsCB cb  =   new  EnumWindowsCB(MyEWP);

从C#程序中调用非受管DLLs [择自博客园]

Win32.EnumWindows(cb,  0 );     

聪明的读者回注意到我们这里掩饰了lparam的问题,在C中,如果你给EnumWindows一个LPARAM,则Windows会用它通知回调函数。一般典型的lparam是一个结构或类指针,其中包含着我们需要的上下文信息。但是记住,在.NET中绝对不能提到"指针"!那么如何做呢?这是可以将lparam声明为IntPtr并用GCHandle对它进行打包: 

从C#程序中调用非受管DLLs [择自博客园]

//  现在lparam 是 IntPtr 

从C#程序中调用非受管DLLs [择自博客园]

delegate   bool  EnumWindowsCB( int  hwnd,     IntPtr lparam);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

//  在GCHandle中打包对象

从C#程序中调用非受管DLLs [择自博客园]

MyClass obj  =   new  MyClass();

从C#程序中调用非受管DLLs [择自博客园]

GCHandle gch  =  GCHandle.Alloc(obj);

从C#程序中调用非受管DLLs [择自博客园]

EnumWindowsCB cb  =   new  EnumWindowsCB(MyEWP);

从C#程序中调用非受管DLLs [择自博客园]

   Win32.EnumWindows(cb, (IntPtr)gch);

从C#程序中调用非受管DLLs [择自博客园]

   gch.Free();       

最后不要忘了调用Free! C#中有时也需要与以往一样必须要我们自己释放占用的内存。为了存取载枚举器中的lparam"指针",必须使用

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

GCHandle.Target。  public   static   bool  MyEWP( int  hwnd, IntPtr param) 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

  GCHandle gch = (GCHandle)param;

从C#程序中调用非受管DLLs [择自博客园]

  MyClass c = (MyClass)gch.Target;

从C#程序中调用非受管DLLs [择自博客园]

  // 

从C#程序中调用非受管DLLs [择自博客园]

 use it

从C#程序中调用非受管DLLs [择自博客园]

  return true;

从C#程序中调用非受管DLLs [择自博客园]

}       

从C#程序中调用非受管DLLs [择自博客园]

下面是一个窗口数组类: //

WinArray.cs

从C#程序中调用非受管DLLs [择自博客园]

//  WinArray: 用EnumWindows 产生顶层窗口的清单ArrayList 

从C#程序中调用非受管DLLs [择自博客园]

//

从C#程序中调用非受管DLLs [择自博客园]

using  System;

从C#程序中调用非受管DLLs [择自博客园]

using  System.Collections;

从C#程序中调用非受管DLLs [择自博客园]

using  System.Runtime.InteropServices;

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

namespace  WinArray 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

   public class WindowArray : ArrayList 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

      private delegate bool EnumWindowsCB(int hwnd, IntPtr param);

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      // 这里声明的是private类型的委托,因为只有我使用它,其实没必要这样做。

从C#程序中调用非受管DLLs [择自博客园]

      [DllImport("user32")]

从C#程序中调用非受管DLLs [择自博客园]

      private static extern int EnumWindows(EnumWindowsCB cb, 

从C#程序中调用非受管DLLs [择自博客园]

         IntPtr param); 

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      private static bool MyEnumWindowsCB(int hwnd, IntPtr param) 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

         GCHandle gch = (GCHandle)param;

从C#程序中调用非受管DLLs [择自博客园]

         WindowArray itw = (WindowArray)gch.Target;

从C#程序中调用非受管DLLs [择自博客园]

         itw.Add(hwnd);

从C#程序中调用非受管DLLs [择自博客园]

         return true;

从C#程序中调用非受管DLLs [择自博客园]

      }

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      // 这是唯一的public 类型方法,你需要调用的唯一方法

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

      public WindowArray() 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

         GCHandle gch = GCHandle.Alloc(this);

从C#程序中调用非受管DLLs [择自博客园]

         EnumWindowsCB ewcb = new EnumWindowsCB(MyEnumWindowsCB);

从C#程序中调用非受管DLLs [择自博客园]

         EnumWindows(ewcb, (IntPtr)gch);

从C#程序中调用非受管DLLs [择自博客园]

         gch.Free();

从C#程序中调用非受管DLLs [择自博客园]

      }

从C#程序中调用非受管DLLs [择自博客园]

   }

从C#程序中调用非受管DLLs [择自博客园]

}       

从C#程序中调用非受管DLLs [择自博客园]

这个类将EnumWindows封装在一个数组中,不用我们再去进行繁琐的委托和回调,我们可以象下面这样轻松使用这个类: 

从C#程序中调用非受管DLLs [择自博客园]

WindowArray wins  =   new  WindowArray();

从C#程序中调用非受管DLLs [择自博客园]
从C#程序中调用非受管DLLs [择自博客园]

foreach  ( int  hwnd  in  wins) 

从C#程序中调用非受管DLLs [择自博客园]

{

从C#程序中调用非受管DLLs [择自博客园]

 // do something

从C#程序中调用非受管DLLs [择自博客园]

}        

是不是很帅啊!我们甚至还可以在受管C++中使用DllImport风格的包装类。在.NET环境中,只要能进行相应的转换,便可以在受管和非受管世界之间随心所欲地聘驰, 大多数情况下的转换是自动的,不必关心太多的事情。需要进行MarshalAs或者打包GCHandle的情况很少。有关C#和非受管C++之间的平台调用的其它细节问题,可以参考.NET的有关文档。 下面是本文提供的一个带有开关的控制台小程序ListWin。它的功能是列出所有顶层窗口,输出可以显示HWNDs、窗口类名、窗口标题以及窗口矩形,用RECT或Rectangle。这些内容的显示可用开关控制。 //