当前位置:首页 > C# > 正文内容

C#调用c++的dll执行带参数的函数时 请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配

admin2年前 (2023-04-03)C#3866

C#动态调用DLL

由于Dll路径的限制,使用的不是很方便,C#中我们经常通过配置动态的调用托管Dll,例如常用的一些设计模式:Abstract Factory, Provider, Strategy模式等等,那么是不是也可以这样动态调用C++动态链接呢?只要您还记得在C++中,通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中),那么问题迎刃而解了,下面我们一步一步实验

将kernel32中的几个方法封装成本地调用类NativeMethod

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace InteropDemo
{
    public static class NativeMethod
    {
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        public static extern int LoadLibrary(
            [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        public static extern IntPtr GetProcAddress(int hModule,
            [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        public static extern bool FreeLibrary(int hModule);
    }
}



使用NativeMethod类动态读取C++Dll,获得函数指针,并且将指针封装成C#中的委托。原因很简单,C#中已经不能使用指针了,如下          
            int hModule = NativeMethod.LoadLibrary(@"c:"CppDemo.dll");

            IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");

详细请参见代码 

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace InteropDemo
{
    class Program
    {
        //[DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
        //public static extern int Add(int a, int b); //DllImport请参照MSDN


        static void Main(string[] args)
        {
            //1. 动态加载C++ Dll
            int hModule = NativeMethod.LoadLibrary(@"c:\CppDemo.dll");
            if (hModule == 0) return;

            //2. 读取函数指针
            IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");

            //3. 将函数指针封装成委托
            Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add));

            //4. 测试
            Console.WriteLine(addFunction(1, 2));
            Console.Read();
        }

        /// <summary>
        /// 函数指针
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        delegate int Add(int a, int b);

    }
}


报错信息是:托管调试助手“PInvokeStackImbalance”在“E:\WCF\CPP\bin\test.vshost.exe”中检测到问题。

其他信息: 对 PInvoke 函数“test!test.FUNC1::Invoke”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。

解决方法:

C#默认是stdcall调用约定,你可以把委托改成下面写法
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
delegate int FUNC1(string xmlSta, StringBuilder fileOut);



扫描二维码推送至手机访问。

版权声明:本文由视觉博客发布,如需转载请注明出处。

本文链接:https://feelsight.cn/post/140.html

“C#调用c++的dll执行带参数的函数时 请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配” 的相关文章

UDP打洞原理及代码

UDP"打洞"原理 1.       NAT分类根据Stun协议(RFC3489),NAT大致分为下面四类1)      Full Cone这种NAT内部的机器...

UDP穿透NAT的原理与实现(UDP“打洞”原理)

NAT(The IP Network Address Translator) 的概念和意义是什么?NAT, 中文翻译为网络地址转换。具体的详细信息可以访问RFC 1631 - http://www.faqs.org/rfcs/rfc1631.html, 这是对于NAT的定义和解释的最权威的...

 C#图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)

C#图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)

一、各种旋转、改变大小 注意:先要添加画图相关的using引用。 //向右旋转图像90°代码如下: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {...

C#实现邮件发送的功能

很多时候需要邮件发送功能,例如:监测应用,需要上报状态。   微软封装好的MailMessage类:主要处理发送邮件的内容(如:收发人地址、标题、主体、图片等等)   微软封装好的SmtpClient类:主要处理用smt...

C# 窗体间传值(Form与From之间互相传值)

C# 窗体间传值(Form与From之间互相传值)

1、委托   两个窗体,窗体很简单,只实现改变颜色功能,一看就会: 代码如下,只贴按钮事件代码: 打开Form2按钮事件 private void button1_Click(object s...

高恪路由器批量管理监控系统

高恪路由器批量管理监控系统

一、采用C# 编写,可以批量监控路由器是否正常 功能: 1.显示当前路由IP、名字、实时上行速度、实时下行速度、主机数量、连接数、CPU占用率、内存占用率、CPU温度、运行时间等 2.可以显示10分钟实时流量 3.可以显示历史2小时、...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。