在C#调用动态库时有没有遇到过“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的错误信息,这里告诉你两个原因。

捕捉到的错误提示是这样的:

System.AccessViolationException: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏

我用delphi尝试去寻找造成这个错误的原因。先用delphi写一个动态库,方法如下:

function Hello(Name:pchar):pchar; export;
 var
 myStr :string;
 begin
   myStr:='hi!' + string(Name);
   result:=pchar(myStr);
 end;

用C#调用

[DllImport("minmax.dll", CharSet = CharSet.Ansi)]
public static extern string Hello(string pName);

调用Hello("kevin")真的出现我期待的错误。于是在以为调整对字符的处理就能解决。

function Hello1(Name:pchar):pchar; export;
 var
  Buffer:pchar;
  maxSize:integer;
 begin
   maxSize := sizeof(Name);
   GetMem(Buffer,maxSize);
  StrCopy(Buffer,Name);
   result:=Buffer;
 end;

其实两个方法对于字符串的操作都没有问题,问题是方法定义少了“stdcall”,调用第一行代码

function Hello1(Name:pchar):pchar;stdcall; export;

两个方法在C#调用都没有问题了。到此我的问题想是找到方向了,但我意外发现一个有趣的现象,于是我想根究一下。因为我遇到问题的函数也是返回一个long。为了简化描述,delphi里的方法是这样,直接就返回-1

function Hello2(pint:LongInt;row:integer;pname:pchar; pvalue:pchar):integer; stdcall; export;
 begin
   result:=-1;
 end;

C#里是这样定义这个外部函数的

[DllImport("minmax.dll", CharSet = CharSet.Ansi)]
public static extern long Hello2(long pint, int row, string pname, string pvalue);

C#里调用Hello2会得到一个很大的数!并不是我所期待的-1!因为对delphi并不很熟悉,曾为了返回long用什么类型翻了书本,记得其longint其实是一个32的数字。于是将C#的定义语句的返回类型修改为int。结果-1如期的来了!这为我下面找到另一个内存损坏打好了基础!

因为工作中需要调用的方法delphi是可以调用的,但C#调用就是了出错,于是想通过delphi做一个动态库作为中间包来使用,

FUNCTION put2 ( pint:LongInt; row:integer; pname:pchar; pvalue:pchar):integer; stdcall; export;
var
 bufferVal:pchar;
 maxSize:integer;
begin
   maxSize := sizeof(pvalue);
   GetMem(bufferVal,maxSize);
   StrCopy(bufferVal,pvalue);
   //调用目标库的方法
   result:=-1;
end;

C#里这样定义上面的外部函数

[DllImport("minmax.dll", CharSet = CharSet.Ansi)]
public static extern int put2(long pint, long row, string pname, string pvalue);

C#里调用put2也出现了内存损坏的提示。为什么呢?难道只因为put2比Hello1多了两个long的参数?!脑袋突然闪过一个念头,难道C++和delphi的long都32位,C#是64位,两者对于long分配的内存大小不同!尝试修改C#的外部函数定义

[DllImport("minmax.dll", CharSet = CharSet.Ansi)]
public static extern int put2(int pint, int row, string pname, string pvalue);

问题解决!