寫這篇博文為了說明如何"托管"與'"非托管"互用問題。具體來講包括:如何在托管代碼中使用非托管代碼、如何在托管代碼中使用非托管dll、如何在非托管代碼中使用托管dll以及托管代碼。直接給出最直接的描述---代碼。
1.托管代碼中使用非托管代碼
給出個可行示例,簡單的說明下下面這段代碼的功能--“灰度化”圖像。
//托管代碼調用非托管代碼 //DebugLZQ以前寫的 //unsafe{}中代碼為非托管代碼 private void pointer_Click(object sender, EventArgs e) { if (curBitmap != null) { myTimer.ClearTimer(); myTimer.Start(); Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat); byte temp = 0; unsafe { byte* ptr = (byte*)(bmpData.Scan0); for (int i = 0; i < bmpData.Height; i++) { for (int j = 0; j < bmpData.Width; j++) { temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]); ptr[0] = ptr[1] = ptr[2] = temp; ptr += 3; } ptr += bmpData.Stride - bmpData.Width * 3; } } curBitmap.UnlockBits(bmpData); myTimer.Stop(); timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒"; Invalidate(); } }
為了使程序能正確執行,需要設置項目的屬性生成為:“允許不安全代碼”。
這樣程序就可正常運行,效果如下:
2.托管代碼中使用非托管dll
前面在講計時器的時候提到過,下面給出一個完整可用的高性能計時器,順便給出調用非托管dll的示例。代碼如下:
using System; using System.Runtime.InteropServices; using System.ComponentModel; using System.Threading; //DebugLZQ //www.cnblogs.com/DebugLZQ //這是使用的一個計時器,拿這個來說明如何在托管代碼中使用非托管dll namespace gray { internal class HiPerfTimer { [DllImport("Kernel32.dll")] private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); [DllImport("Kernel32.dll")] private static extern bool QueryPerformanceFrequency(out long lpFrequency); private long startTime, stopTime; private long freq; // Constructor public HiPerfTimer() { startTime = 0; stopTime = 0; if (QueryPerformanceFrequency(out freq) == false) { // high-performance counter not supported throw new Win32Exception(); } } // Start the timer public void Start() { // lets do the waiting threads there work Thread.Sleep(0); QueryPerformanceCounter(out startTime); } // Stop the timer public void Stop() { QueryPerformanceCounter(out stopTime); } // Returns the duration of the timer (in milliseconds) public double Duration { get { return (double)(stopTime - startTime) * 1000 / (double)freq; } } public void ClearTimer() { startTime = 0; stopTime = 0; } } }
用法很簡單:
private HiPerfTimer myTimer=new HiPerfTimer(); myTimer.Start(); myTimer.Stop(); myTimer.Duration//wanted
再寫一個例子
using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading; namespace PInvoke { class Program { static void Main(string[] args) { if (!MessageBeep(0)) { //不會執行 Int32 err = Marshal.GetLastWin32Error(); throw new Win32Exception(err); } } [DllImport("User32.dll")] private static extern Boolean MessageBeep(UInt32 beepType); } }
3-4.非托管代碼中調用托管dll、寫托管代碼。
前一篇博文談到CLR宿主的時候,遇到過這個問題,托管Assembly代碼如下:
using System; namespace NET.MST.Eighth.SimpleAssembly { /// <summary> /// 一個簡單的“托管”程序集,功能是輸出傳入的字符串 /// </summary> public class SimpleAssembly { static int WriteString(String s) { Console.WriteLine("CLR Host Output:" + s); return 1; } } }
在非托管代碼中加載CLR運行托管代碼,代碼如下:
//DebugLZQ //http://www.cnblogs.com/DebugLZQ //C++工程中加載CLR,運行托管代碼 #include "stdafx.h" #include <windows.h> //這里定義加載哪個版本的CLR #include <MSCorEE.h> #pragma comment(lib,"MSCorEE.lib") //加載CLR,從而運行托管代碼 void main(int argc, _TCHAR* argv[]) { ICLRRuntimeHost *pHost; HRESULT hr=CorBindToRuntimeEx( NULL, NULL, , CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&pHost); pHost->Start(); ICLRControl* clrControl = NULL; hr = pHost->GetCLRControl(&clrControl); DWORD* returnvalue=NULL; //開始運行托管代碼 pHost->ExecuteInDefaultAppDomain( L"..\\..\\..\\SimpleAssembly\\bin\\Debug\\SimpleAssembly.dll", L"NET.MST.Eighth.SimpleAssembly.SimpleAssembly", L"WriteString", L"http://www.cnblogs.com/DebugLZQ", returnvalue); system("pause"); //結束時卸載CLR }
程序運行結果如下:
文章旨在給出了一種“托管”--“非托管”互相調用的切實可行的方法,沒有什么可圈可點的地方,請“牛人”勿噴擊DebugLZQ。當然,如果你覺得這篇博文對你有幫助,請點擊下面的“綠色通道”---“關注DebugLZQ”,共同交流進步~