拖不托管是浮云——飘过托管的边界
写这篇博文为了说明如何"托管"与'"非托管"互用问题。具体来讲包括:如何在托管代码中使用非托管代码、如何在托管代码中使用非托管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”,共同交流进步~