一、問(wèn)題:C#調(diào)用C++的DLL 出現(xiàn):“嘗試讀取或?qū)懭胧鼙Wo(hù)的內(nèi)存”
C#的函數(shù)聲明如下:
[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);
這里的返回參數(shù)是string
類型致稀,運(yùn)行程序的時(shí)候直接報(bào)錯(cuò),程序閃退呢簸,但是用別的語(yǔ)言調(diào)用兽泄,同樣的參數(shù)和返回類型漓概,卻可以實(shí)現(xiàn)。
二病梢、嘗試的解決方法:
1胃珍、將CallingConvention = CallingConvention.StdCall
改為CallingConvention = CallingConvention.Cdecl
, 無(wú)效, 提示和參數(shù)類型不匹配
2蜓陌、采用動(dòng)態(tài)調(diào)用DLL的方式觅彰,VS 設(shè)置項(xiàng)目屬性里設(shè)置“允許非安全代碼”、“允許使用原生代碼調(diào)試”钮热,Debug的時(shí)候可以填抬,運(yùn)行時(shí)候報(bào)錯(cuò),程序強(qiáng)制退出
三隧期、最終的解決方案
C#的函數(shù)聲明將原來(lái)的返回值由string
改為IntPr
, 調(diào)用的時(shí)候使用Marshal.PtrToStringAnsi
獲取到最終的string值飒责, 解決問(wèn)題
四、測(cè)試的程序代碼
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);
}