一、问题: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);
}