拖不托管是浮雲——飄過托管的邊界


  寫這篇博文為了說明如何"托管"與'"非托管"互用問題。具體來講包括:如何在托管代碼中使用非托管代碼、如何在托管代碼中使用非托管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”,共同交流進步~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM