.NET简谈互操作(五:基础知识之Dynamic平台调用)

互操作系列文章:

  1. .NET简谈互操作(一:开篇介绍)

  2. .NET简谈互操作(二:先睹为快)

  3. .NET简谈互操作(三:基础知识之DllImport特性)

  4. .NET简谈互操作(四:基础知识之Dispose非托管内存)

  5. .NET简谈互操作(五:基础知识之Dynamic平台调用)

  6. .NET简谈互操作(六:基础知识之提升平台调用性能)

  7. .NET简谈互操作(七:数据封送之介绍)

我们继续.NET互操作学习。在上篇文章中我们学习了关于托管与非托管内存Dispose(释放)问题;下面我们继续学习基础知识中的Dynamic(动态)平台调用技术;

在前几篇文章中,我们都是采用按部就班的方式来调用非托管代码的,先定义非托管代码的托管定义,然后用DllImport来标识相关调用约定;这篇文章我们将介绍怎么通过动态的方式调用非托管代码;在进行讲解之前我们有必要简单的了解一下,托管代码调用非托管代码的大概的步骤或者说是相关细节吧;只有当我们脑子里有一套属于自己的理解思路时,文章才显的有价值;[王清培版权所有,转载请给出署名]

平台调用过程原理

文字使用始终没有图片的表达性强,我们还是来看图吧;

图1:

这幅图画的不是很全,但是大概能表达意思了;

当我们第一次调用非托管DLL文件的时候(穿插一下,这里就牵扯到为什么有些东西必须由操作系统来处理,为什么要有内核,就是用来处理一些我们平时不能随便动的东西,就拿LoadLibrary方法来讲,可能它就是进入了内核然后设置相关参数,帮我们保存了非托管DLL在内存的代理存根,当我们下次又进入到内核的时候,系统去检查一下,发现有过一次调用了,所以下次就去读取存根中的地址进行调用),系统会去加载非托管DLL文件到内存并设置相关数据,以便后期使用;动态调用的原理就是我们把这部分的工作自己手动来做,比如第一次调用非托管DLL肯定是要慢于后面调用的;所以在一些必要的场合下,我们真的有必要进行动态P/Invoke;

动态平台调用示例1

在托管的.NET中我们可以通过使用Win32API中的LoadLibrary方法来手动加载非托管DLL到内存来;

 [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
 public static extern IntPtr LoadLibrary(string iplibfilenmae);

这样的操作就好比我们图1中的第一次调用过程要执行的操作;

 [DllImport("Win32DLL.dll", EntryPoint = "add", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 private static extern int add(int x, int y);

同样我们还是申明非托管代码的定义,我们来看全部代码;

namespace CSharp.Interop
{
    /// <summary>
    /// 动态平台调用,手动加载非托管DLL文件
    /// </summary>
    public static class DynamicPinvoke
    {
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        public static extern IntPtr LoadLibrary(string iplibfilenmae);
        [DllImport("Win32DLL.dll", EntryPoint = "add", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int add(int x, int y);
        public static void Test()
        {
            string currentdirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            string dllpath = Path.Combine(currentdirectory, "Win32DLL.dll");
            IntPtr dlladdr = LoadLibrary(dllpath);
            if (dlladdr == IntPtr.Zero)
                throw new DllNotFoundException(string.Format("在{0}未能找到相关DLL文件", dllpath));

            int addnumber = add(10, 20);
            Console.Write(addnumber);
        }
    }
}

动态平台调用示例2

第一个示例我们是省略了系统调用过程,我们手动调用LoadLibrary来加载;可能没啥大的变化,示例2是通过非托管函数委托来进行动态调用的;

都知道托管委托就好比非托管的函数指针,幸好微软为我们提供了委托来调用非托管方法,适合真的很强大;请看代码;

[UnmanagedFunctionPointer(CallingConvention.StdCall)][王清培版权所有,转载请给出署名]
delegate int add(int x, int y);

系统特性能改变代码的编译行为,所以我们有理由相信我们的add委托已经变成了非托管代码的引用;

namespace CSharp.Interop
{
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate int add(int x, int y);
    public static class DelegateInvoke
    {
        public static void Test()
        {
            string currentdirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            string dllpath = Path.Combine(currentdirectory, "Win32DLL.dll");
            IntPtr dlladdr = Interop.DynamicPinvoke.LoadLibrary(dllpath);
            if (dlladdr == IntPtr.Zero)
                throw new DllNotFoundException(string.Format("在{0}未能找到相关DLL文件", dllpath));
            IntPtr procadd = Win32Api.GetProcAddress(dlladdr, "_add@8");
            if (procadd == IntPtr.Zero)
                throw new DllNotFoundException(string.Format("未能在内存中找到{0}入口点", Marshal.PtrToStringUni(dlladdr)));
            add adddelegate = (add)Marshal.GetDelegateForFunctionPointer(procadd, typeof(add));
            int result = adddelegate(10, 20);
            bool isfree = Win32Api.FreeLibrary(dlladdr);
        }
    }
}

 这段小小的代码里,深藏了很多技术细节;非托管代码导出调用方法时我们需要知道函数名被重整成啥样了,所以本人上传了PE文件查看器http://files.cnblogs.com/wangiqngpei557/PEinfo.zip,通过这个工具我们查看非托管代码的具体信息;这样便于我们调用;

Marshal是一个很强大的P/Invoke的类,可以将它看成是平台调用的体现吧,Marshal.GetDelegateForFunctionPointer方法是通过非托管内存指针获取UnmanagedFunctionPointer类型的委托;

总结:其实动态调用就是让我们竟可能的多去接触底层知识,一切都是可以理解的,只是功夫没到家;

时间: 2024-10-02 20:52:26

.NET简谈互操作(五:基础知识之Dynamic平台调用)的相关文章

.NET简谈互操作(六:基础知识之提升平台调用性能)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.本篇文章我们将来学习互操作基础知识中的最后一个知识点"提升平台调用的性能": 在于非托管函数进

.NET简谈互操作(三:基础知识之DllImport特性)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之释放非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习,上一篇文章中我们介绍了托管代码怎么与非托管代码C++之间的互操作:要想在托管代码中成功的进行非托管调用,要注意的细

.NET简谈互操作(四:基础知识之Dispose非托管内存)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用)  .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.前一篇文章中我们学习了基础知识中的DllImport关键特性:我们继续学习基础知识中的内存释放相关技术

.NET简谈互操作(七:数据封送之介绍)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.互操作的基础知识已经差不多完了,当然一篇小小的文章很难全面的讲述互操作的方方面面,本人只是总结出关键的地

.NET简谈互操作(二:先睹为快)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之释放非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习,为了揭开互操作的神秘面纱,今天这篇文章我们就来先睹为快,让我们先来做个例子,基础的东西,我们陆续进行讲解:由于互操

.NET简谈互操作(一:开篇介绍)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之释放非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 本人最近在学习非托管C++互操作的技术,有点小收获不敢私藏拿出来跟大家分享:作为.NET开发人员,我们有必要学习一些互操作方面的知识:尤其对一

Javascript浅谈之this_基础知识

介绍this在各种对面对象编程中起着非常重要的作用,主要用于指向调用的对象.不过在JavaScript中,this的表现存在很大差异,特别是不同执行上下文. 由前文我们知道this也是属于执行上下文中的一个属性,所有它命中注定和执行上下文脱不了干系. 复制代码 代码如下: activeExecutionContext = {VO: {...},this: thisValue}; 在Javascript中,this的取值取决于调用的模式.调用模式一共有四种:方法调用模式.函数调用模式.构造器调用模

浅谈JavaScript 标准对象_基础知识

在JavaScript的世界里,一切都是对象. 但是某些对象还是和其他对象不太一样.为了区分对象的类型,我们用typeof操作符获取对象的类型,它总是返回一个字符串: typeof 123; // 'number' typeof NaN; // 'number' typeof 'str'; // 'string' typeof true; // 'boolean' typeof undefined; // 'undefined' typeof Math.abs; // 'function' ty

浅谈javascript中关于日期和时间的基础知识_基础知识

前面的话 在介绍Date对象之前,首先要先了解关于日期和时间的一些知识.比如,闰年.UTC等等.深入了解这些,有助于更好地理解javascript中的Date对象.本文将介绍javascript关于日期和时间的基础知识 标准时间一般而言的标准时间是指GMT和UTC,以前是GMT,现在是UTC GMT 格林尼治标准时间(GMT)是指位于伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线 理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空