惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
O
OpenAI News
Y
Y Combinator Blog
MyScale Blog
MyScale Blog
C
Check Point Blog
Vercel News
Vercel News
小众软件
小众软件
The Register - Security
The Register - Security
N
News and Events Feed by Topic
腾讯CDC
S
SegmentFault 最新的问题
H
Heimdal Security Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Schneier on Security
Schneier on Security
G
GRAHAM CLULEY
云风的 BLOG
云风的 BLOG
S
Schneier on Security
J
Java Code Geeks
L
LINUX DO - 最新话题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Privacy & Cybersecurity Law Blog
Forbes - Security
Forbes - Security
Cisco Talos Blog
Cisco Talos Blog
L
LINUX DO - 热门话题
Scott Helme
Scott Helme
爱范儿
爱范儿
GbyAI
GbyAI
Simon Willison's Weblog
Simon Willison's Weblog
L
Lohrmann on Cybersecurity
Cloudbric
Cloudbric
W
WeLiveSecurity
The Hacker News
The Hacker News
V
V2EX
Last Week in AI
Last Week in AI
Hacker News: Ask HN
Hacker News: Ask HN
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
Cyberwarzone
Cyberwarzone
Google Online Security Blog
Google Online Security Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Security @ Cisco Blogs
P
Proofpoint News Feed
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
U
Unit 42
Webroot Blog
Webroot Blog
Martin Fowler
Martin Fowler
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed

博客园 - 同洲共际海让路

国内首本全面深入介绍.NET互操作技术(P/Invoke『或PInvoke,平台调用』,C++ Interop『C++/CLI』,COM Interop)的参考书籍 博客园开发者征途系列图书——《你必须知道的.NET》 一站式查询八字、五行、星座、五格——美名腾人名解析 一句话让别人立马记住你的名字——美名腾智能人名解析 何谓智能起名? 美名腾智能起名系统有了新界面 千名万名,到美名腾来试金。【写在美名腾起名系统Beta版成功发布】 [原]Bug Report,已提交给微软。平台调用调试时,无法对非托管函数进行单步的错误 [原]动态平台调用 part 2 [原]动态平台调用 part 1 JavaScript Debugging and Intellisense, JavaScript obfuscator etc from VS 2005 to VS 2008 (VS2005到2008的变迁,JavaScript调试,智能感知/智能感应功能,JavaScript的混淆、压缩等功能的海变桑田) 终于见到了传说中的Scott Guthrie 如何为Team Foundation Server的Daily Build添加自定义操作 客户端安装Team Explorer 2005后,使用时出现package load failure错误的修正 WCF Part 7 : Bindings WCF Part 6 : Address 推荐一个好玩的好东西,ILMerge,微软出的,合并多个.NET组件成一个 WCF Part 5 : Consuming the service [译]WCF Part 4 : Make your service visible through metadata
[原]动态平台调用 part 3 (Final)
同洲共际海让路 · 2008-07-24 · via 博客园 - 同洲共际海让路

前面讲述了两种采用平台调用的技术,分别是动态平台调用 part 1动态平台调用 part 2

上面两篇文章介绍了两种不同的进行动态平台调用的方法。这两种方法也是在.NET Framework 1.01.1下进行动态平台调用的主要方法。从.NET Framework 2.0起,引入了一个能够用于进行动态平台调用的新技术,那就是Marshal.GetDelegateForFunctionPointer。使用这种方法动态加载非托管DLL并调用其中的非托管函数,其主要步骤如下:

(1)       为非托管函数定义一个委托;

(2)       使用Win32 API函数LoadLibrary加载需要调用的非托管DLL

(3)       使用Win32 API函数GetProcAddress获得非托管函数的地址;

(4)       使用Marshal.GetDelegateForFunctionPointer将上面获得的函数地址封送到第一步定义的委托;

(5)       使用代理调用函数,获得结果;

(6)       使用Win32 API函数FreeLibrary释放之前加载的非托管DLL

下面的代码演示了采用上面所介绍的方法,对非托管函数进行动态平台调用的过程。

class DynamicPInvokeViaDelegate

{

[UnmanagedFunctionPointer(CallingConvention.StdCall)]

    delegate int MultiplyDelegate(int factorA, int factorB);

    public static void Test()

    {

        string entryPoint = "_Multiply@8";

        string currentDirectory =

                            Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

        string dllPath = Path.Combine(currentDirectory,

            @"nativelibfordynamicpinvoke\NativeLibForDynamicPInvoke.dll");

        //动态加载需要平台调用的非托管DLL

        IntPtr dllAddr = Win32API.LoadLibrary(dllPath);

        if (dllAddr == IntPtr.Zero)

        {

            throw new DllNotFoundException(string.Format("Can not load {0}, please check.",

                dllPath));

        }

        //获得需要调用的函数的地址

        IntPtr procAddr = Win32API.GetProcAddress(dllAddr, entryPoint);

        if (procAddr == IntPtr.Zero)

        {

            throw new EntryPointNotFoundException(

                string.Format("Can not find entry point \"{0}\" in dll \"{1}\", please check.",

                entryPoint, dllPath));

        }

        //使用代理来封送函数指针

        MultiplyDelegate multiplyDelegate =

            (MultiplyDelegate)Marshal.GetDelegateForFunctionPointer(

            procAddr, typeof(MultiplyDelegate));

        //调用非托管函数

        int factorA = 100, factorB = 8;

        int result = multiplyDelegate(factorA, factorB);

//释放加载的DLL

        bool isFree = Win32API.FreeLibrary(dllAddr);

        if (isFree)

        {

            Console.WriteLine("Successfully  free {0}.",

                Path.GetFileName(dllPath));

        }

        else

        {

            throw new Exception(string.Format("Can not free {0}.",

                Path.GetFileName(dllPath)));

        }

        //打印结果

        Console.WriteLine(string.Format("{0} * {1} = {2} ", factorA, factorB, result));

        Console.WriteLine("Press any key to exit.");

        Console.Read();

    }

}

在上面的代码中,需要特别注意粗体部分。在为非托管函数定义委托时,委托的参数类型和返回值类型必须同将要调用的非托管函数完全匹配。而委托的名称可以不同。在定义委托时,可以给其加上UnmanagedFunctionPointer属性,也可以不加,采用默认值。通过设置UnmanagedFunctionPointerCallingConvention属性,CharSetSetLastError等字段,可以控制作为非托管函数指针传入或传出非托管代码的委托签名的封送行为。由于UnmanagedFunctionPointerMarshal.GetDelegateForFunctionPointer都是.NET Framework 2.0以上版本才有的特性,因此这种动态平台调用的方法只适合.NET Framework 2.0以上版本。

此外,在使用GetProcAddress函数获得要调用的非托管函数的地址时,传递的函数名必须是经过重整后的名称。由于本示例所采用的非托管DLL在导出函数时,使用了extern "C",并采用了__stdcall这个调用约定,因此最终导出的函数名就会被重整成_Multiply@8。这样就要求在使用GetProcAddress方法获得非托管函数的地址时,必须传递同非托管DLL导出的实际函数名完全相同的名称。

运行Test方法进行测试,同样也能获得完全相同的结果:

100 * 8 = 800

Press any key to exit.

本系列讲述了进行动态平台调用的三种主要方法。前两种方法适用于目前所有.NET Framework 版本(1.01.12.03.0+)。而第三种方法,只适用于.NET Framework 2.0以上版本。需要特别注意的就是,在使用第二种方法和第三种方法时,指定的函数入口点,必须同非托管DLL导出的实际函数名完全一致。