由於工作需要,學習了GDI+編程的一些知識。其中看到了一個比較好的Demo,深入的瞭解後,卻發現自己對如何用C#調用非託管DLL函數也有了更好的理解,於是整理了一下,跟大家一起分享。
C#捕獲當前螢幕的例子
#region C#捕獲當前螢幕的例子
using System ;
using System.Drawing ;
using System.Collections ;
using System.ComponentModel ;
using System.Windows.Forms ;
using System.Data ;
using System.Drawing.Imaging ;
public class Form1 : Form
{
private Button button1 ;
private System.ComponentModel.Container components = null ;
public Form1 ( )
{
//初始化表單中的各個組件
InitializeComponent ( ) ;
}
// 清除程式中使用過的資源
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
components.Dispose ( ) ;
}
}
base.Dispose ( disposing ) ;
}
private void InitializeComponent ( )
{
button1 = new Button ( );
SuspendLayout ( ) ;
button1.Location = new System.Drawing.Point ( 64 , 40 ) ;
button1.Name = "button1" ;
button1.Size = new System.Drawing.Size ( 80 , 32 ) ;
button1.TabIndex = 0 ;
button1.Text = "捕獲" ;
button1.Click += new System.EventHandler ( button1_Click ) ;
AutoScaleBaseSize = new System.Drawing.Size ( 6 , 14 ) ;
ClientSize = new System.Drawing.Size ( 216 , 125 ) ;
Controls.Add ( button1 ) ;
MaximizeBox = false ;
MinimizeBox = false ;
Name = "Form1" ;
Text = "C#捕獲當前螢幕!" ;
ResumeLayout ( false ) ;
}
//聲明一個API函數
[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目標 DC的控制代碼
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的控制代碼
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光柵的處理數值
) ;
static void Main ( )
{
Application.Run ( new Form1 ( ) ) ;
}
private void button1_Click ( object sender , System.EventArgs e )
{
//獲得當前螢幕的大小
Rectangle rect = new Rectangle ( ) ;
rect = Screen.GetWorkingArea ( this ) ;
//建立一個以當前螢幕為模板的圖象
Graphics g1 = this.CreateGraphics ( ) ;
//建立以螢幕大小為標準的位元影像
Image MyImage = new Bitmap ( rect.Width , rect.Height , g1 ) ;
Graphics g2 = Graphics.FromImage ( MyImage ) ;
//得到螢幕的DC
IntPtr dc1 = g1.GetHdc ( ) ;
//得到Bitmap的DC
IntPtr dc2 = g2.GetHdc ( ) ;
//調用此API函數,實現螢幕捕獲
BitBlt ( dc2 , 0 , 0 , rect.Width , rect.Height , dc1 , 0 , 0 , 13369376 ) ;
//釋放掉螢幕的DC
g1.ReleaseHdc ( dc1 ) ;
//釋放掉Bitmap的DC
g2.ReleaseHdc ( dc2 ) ;
//以JPG檔案格式來儲存
MyImage.Save ( @"c:\Capture.jpg" , ImageFormat.Jpeg );
MessageBox.Show ( "當前螢幕已經儲存為C盤的capture.jpg檔案!" ) ;
}
}
#endregion
上面的例子中,應用C#調用非託管DLL的函數如下:
//聲明一個API函數
[ System.Runtime.InteropServices.DllImportAttribute ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest , // 目標 DC的控制代碼
int nXDest ,
int nYDest ,
int nWidth ,
int nHeight ,
IntPtr hdcSrc , // 源DC的控制代碼
int nXSrc ,
int nYSrc ,
System.Int32 dwRop // 光柵的處理數值
) ;
在上面這段代碼中,我將以分別介紹 DllImportAttribute屬性、extern關鍵字 、IntPtr類型 這三個方面,向大家介紹如何應用C#調用非託管DLL函數。
C# 如何使用 DllImport Attribute(屬性) 標識 DLL 和函數
System.Runtime.InteropServices.DllImportAttribute
從Managed 程式碼中訪問非託管 DLL 函數之前,需要知道該函數的名稱以及該 DLL 的名稱,然後為 DLL 的非託管函數 編寫 託管定義。
它將用到 static 和 extern 修飾符,此類型的公用靜態成員對於多線程操作是安全的。
DllImport 屬性提供非託管 DLL 函數的調用資訊。
樣本1 簡單DllImportAttribute 應用
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
public static extern int MessageBox(int hWnd, String text, String caption, uint type);
樣本2 如何將 DllImportAttribute 應用於方法。
using System.Runtime.InteropServices;
[DllImport( "KERNEL32.DLL",
EntryPoint="MoveFileW",
SetLastError=true,
CharSet=CharSet.Unicode,
ExactSpelling=true,
CallingConvention=CallingConvention.StdCall
)
]
public static extern bool MoveFile(String src, String dst);
參數說明:
EntryPoint 指定要調用的 DLL 進入點。
SetLastError 判斷在執行該方法時是否出錯(使用 Marshal.GetLastWin32Error API 函數來確定)。
C#中預設值為 false。
CharSet 控制名稱及函數中字串參數的編碼方式。預設值為 CharSet.Ansi。
ExactSpelling 是否修改進入點以對應不同的字元編碼方式。
CallingConvention 指定用於傳遞方法參數的呼叫慣例。預設值為 WinAPI。
該值對應於基於32位Intel平台的 __stdcall。
BestFitMapping 是否啟用最佳映射功能,預設為 true。
最佳映射功能提供在沒有匹配項時,自動提供匹配的字元。
無法映射的字元通常轉換為預設的“?”。
PreserveSig 託管方法簽名是否轉換成返回 HRESULT,預設值為 true(不應轉換籤名)。
並且傳回值有一個附加的 [out, retval] 參數的非託管簽名。
ThrowOnUnmappableChar 控制對轉換為 ANSI '?' 字元的不可映射的 Unicode 字元引發異常。
C# 關鍵字 extern 的使用
public static extern int MyMethod(int x);
外部修飾符 extern 用於指示外部實現方法,常與 DllImport 屬性一起使用(DllImport 屬性提供非託管 DLL 函數的調用資訊)。
若將 abstract 和 extern 修飾符一起使用來修改同一成員是錯誤的。extern 將方法在 C# 代碼的外部實現,而 abstract 意味著在此類中未提供此方法的實現。
因為外部方法聲明不提供具體實現,所以沒有方法體;
此方法聲明只是以一個分號結束,並且在簽名後沒有大括弧{ }。
樣本3 接收使用者輸入的字串並顯示在訊息框中
程式從 User32.dll 庫匯入的 MessageBox 方法。
using System;
using System.Runtime.InteropServices;
class MyClass
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
public static int Main()
{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}
}
運行結果: 輸入"Hello"文本後,螢幕上將彈出一個包含該文本的訊息框。
Enter your message: Hello
樣本4 調用DLL進行計算
該樣本使用兩個檔案 CM.cs 和 Cmdll.c 來說明 extern。
C 檔案是從 C# 程式中調用的外部 DLL。
使用 Visual C++ 命令列將 Cmdll.c 編譯為 DLL:
cl /LD /MD Cmdll.c
檔案:Cmdll.c
// cmdll.c
// compile with: /LD /MD
int __declspec(dllexport) MyMethod(int i)
{
return i*10;
}
使用命令列編譯 CM.cs:
csc CM.cs
這將建立可執行檔 CM.exe。
檔案:CM.cs
// cm.cs
using System;
using System.Runtime.InteropServices;
public class MyClass
{
[DllImport("Cmdll.dll")]
public static extern int MyMethod(int x);
public static void Main()
{
Console.WriteLine("MyMethod() returns {0}.", MyMethod(5));
}
}
運行此程式,MyMethod 將值 5 傳遞到 DLL 檔案,該檔案將此值乘以 10 返回。
運行結果:MyMethod() returns 50.
IntPtr 類型的說明
對於平台叫用,應讓參數為 IntPtr 類型,而不是 String 類型。使用 System.Runtime.InteropServices.Marshal 類所提供的方法,可將類型手動轉換為字串並手動將其釋放。
IntPtr 類型被設計成整數,其大小適用於特定平台。
在 32 位硬體和作業系統中將是 32 位;
在 64 位元硬體和作業系統中將是 64 位元。
IntPtr 類型由支援指標的語言使用,並作為在支援與不支援指標的語言間引用資料的一種通用方式。它也可用於保持控制代碼。例如,IntPtr 的執行個體廣泛地用在 System.IO.FileStream 類中來保持檔案控制代碼。
IntPtr 類型符合 CLS 規範,而 UIntPtr 類型卻不符合。只有 IntPtr 類型可用在公用語言運行庫中。此類型實現 ISerializable 介面。
其中引用了微軟官方的部分例子,特此聲名。希望多多指教,共同進步!
來源:http://www.cnblogs.com/xugang/archive/2007/12/23/1011597.html