.NET调用C++ DLL时遇到的问题及解决办法

一、问题:C#调用C++的DLL 出现:“尝试读取或写入受保护的内存”
C#的函数声明如下:

 [DllImport("kmdes.dll", CallingConvention = CallingConvention.StdCall)]
 private static extern string encrypt(string key, string vkey);

[DllImport("kmdes.dll", CallingConvention = CallingConvention.StdCall)]
private static extern string decrypt(string key, string vkey);

这里的返回参数是string类型,运行程序的时候直接报错,程序闪退,但是用别的语言调用,同样的参数和返回类型,却可以实现。

二、尝试的解决方法:
1、将CallingConvention = CallingConvention.StdCall改为CallingConvention = CallingConvention.Cdecl, 无效, 提示和参数类型不匹配
2、采用动态调用DLL的方式,VS 设置项目属性里设置“允许非安全代码”、“允许使用原生代码调试”,Debug的时候可以,运行时候报错,程序强制退出

三、最终的解决方案
C#的函数声明将原来的返回值由string改为IntPr, 调用的时候使用Marshal.PtrToStringAnsi获取到最终的string值, 解决问题

四、测试的程序代码

 class Program
    {
        static void Main(string[] args)
        {
            var pwd = Encrypt("123456", "aa");
            var depwd = Decrypt(pwd, "aa");

            Console.WriteLine("123456加密后: " + pwd);
            Console.WriteLine("解密后: " + depwd);
            Console.ReadKey();
        }

        public static string Decrypt(string source, string key)
        {
            var result = Marshal.PtrToStringAnsi(decrypt(source, key));
            return result;
        }

        public static string Encrypt(string source, string key)
        {
            try
            {
                var result = Marshal.PtrToStringAnsi(encrypt(source, key));
                return result;
            }
            catch (Exception ex)
            {
                return "";
            }

        }

        public string[] GenerateKeys()
        {
            return new string[] { "aa" };
        }

        [DllImport("kmdes.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr encrypt(string key, string vkey);

        [DllImport("kmdes.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr decrypt(string key, string vkey);
    }

    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);
    }

参考文章:
1、http://www.phpfans.net/ask/quiz1/7437998116.html

你可能感兴趣的:(.NET调用C++ DLL时遇到的问题及解决办法)