拖不托管是浮云——飘过托管的边界

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

原文地址:https://www.cnblogs.com/DebugLZQ/p/2636919.html