堆已损坏。C#dllimport,delphi PChar返回值

堆已损坏。C#dllimport,delphi PChar返回值,c#,delphi,dllimport,C#,Delphi,Dllimport,我已经导入了dll。所有其他部分都工作,但imported方法的字符串返回值给出了以下内容: ***.exe:0xC0000374中0x7748EA5F(ntdll.dll)处未处理的异常:堆已损坏(参数:0x774C4270) 它仍然返回字符串,但我担心这会导致以后出现其他一些难以调试的错误。从我测试的结果来看,它可能是导致这种情况的任何原因 这是我的导入代码: [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrar

我已经导入了dll。所有其他部分都工作,但imported方法的字符串返回值给出了以下内容:

***.exe:0xC0000374中0x7748EA5F(ntdll.dll)处未处理的异常:堆已损坏(参数:0x774C4270)

它仍然返回字符串,但我担心这会导致以后出现其他一些难以调试的错误。从我测试的结果来看,它可能是导致这种情况的任何原因

这是我的导入代码:

[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private delegate String GetStringDelegate(int handle, int index);

private static GetStringDelegate getString { get; set; }

var addressOfGetString = NativeMethods.GetProcAddress(_handle, "GetString");
getString = (GetStringDelegate)Marshal.GetDelegateForFunctionPointer(addressOfGetString, typeof(GetStringDelegate));
用法

这是可行的,但会导致错误。调试时,只需按“continue”(继续)即可进行处理并显示结果。结果是正确的

这是如何在delphi dll中完成的

function GetString(Hnd,Index : Integer) : PChar; stdcall;
begin
 Result:=TControl(Hnd).Stack.GetString(Index);
end;
我有相同类型的代码用于整数、double、bools和dll中的所有其他内容,没有错误。所以我认为它会造成某种溢出或内存分配错误

注意:若我创建控制台应用程序,它只是失败了,并没有出现错误,若我在并没有调试器的情况下运行控制台(ctrl+f5),它仍然工作,并没有错误。当我从窗体应用程序调用此函数时,会生成堆错误


TL;博士这段代码可以工作,但它显示了堆错误,同时返回int、bools等非常有效。

当您将字符串作为p/invoke函数的函数返回值返回时,封送拆收器负责释放该内存。它假定内存是在COM堆上分配的,例如使用
CoTaskMemAlloc
。您的字符串不符合该要求

  • 您可以更改Delphi代码以这样分配内存
  • 您可以返回
    IntPtr
    并使用
    Marshal.PtrToStringAnsi
    手动封送。接下来的问题是是否需要释放内存,如果需要,如何释放
  • 您可以返回一个COM BSTR,但这只适用于Delphi作为输出参数,而不是函数返回值。看
  • 您可以要求调用者分配内存,并让被调用者填充内存
我无法确定代码的所有内容,但如果您返回
PChar(s)
,其中
s
是一个局部变量,我也不会感到惊讶。这意味着您将返回已释放内存的地址


这里的底线是,从被调用方向调用方传递字符串(或者实际上是数组或其他动态结构)要比传递简单的值类型复杂得多。您需要重新考虑如何做到这一点

在Delphy的最新版本中,
PCHAR
是Unicode,因此
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet=CharSet.Ansi)]
应该是
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet=CharSet.Unicode)]
@xanatos,除非通常情况下,用户仍在D2007或earlier@DavidHeffernan我写过“在最近的版本中”,如果我将其更改为unicode,字符串是一些中文字母。@Katu表示文本实际上是ANSI和
字符集。ANSI
适用于此DLLI请参见。。我不是dll的作者,但我会告诉他这个答案。谢谢。显然,是框架4.5造成了问题。你的笔记很好,在与作者讨论后,注意到它以前在其他.Net应用程序上工作过,所以我不得不改变方向。必须从盒子里向外看。更改为.net 4有帮助。。无论如何谢谢不,那都错了。您的代码在所有版本的.net上都被破坏,返回到版本1。你只是侥幸逃脱了。这只是一个打破最新框架的机会。我不明白如果你不想理解这个问题,为什么你会问这个问题。当我告诉你马歇尔勒正在给CoTaskMemFree打电话时,你不相信我吗?!谢谢你踢了我一下!您的解决方案是将返回类型从
string
更改为
IntPtr
,然后将
Marshal.PtrToStringAnsi
更改为返回值。我很高兴您坚持了这一点。很高兴切换到
IntPtr
成功了。请随便质疑我的话,持怀疑态度总是明智的。出于同样的原因,问问你自己,在这种情况下,你一定从骨子里知道切换.net framework感觉不对劲!;-)
function GetString(Hnd,Index : Integer) : PChar; stdcall;
begin
 Result:=TControl(Hnd).Stack.GetString(Index);
end;