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

时间:2015-05-20 12:11:29

标签: c# delphi dllimport

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

  

***。exe中0x7748EA5F(ntdll.dll)的未处理异常:0xC0000374:堆已损坏(参数: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));

使用

getString(Handle, 1);

这样可行,但会导致错误。在调试时,只需按下"继续"将允许它处理它并显示结果。结果是正确的。

这是在delphi dll中完成的方法

function GetString(Hnd,Index : Integer) : PChar; stdcall;
begin
 Result:=TControl(Hnd).Stack.GetString(Index);
end;

我有相同类型的整数,双精度,bool和dll中的其他所有代码,没有错误。所以我认为它会产生一些溢出或错误的内存分配大小。

注意:如果我创建控制台应用程序,它只是失败,没有中断错误,如果我在没有调试器的情况下运行控制台(ctrl + f5),它仍然有效,仍然没有错误。当我从表单应用程序中调用它时会生成堆错误。

TL; DR;这段代码有效,但它显示了堆错误,而返回int,bools等工作完美。

1 个答案:

答案 0 :(得分:9)

当您返回一个字符串作为p / invoke函数的函数返回值时,marshaller负责释放该内存。它假定内存是在COM堆上分配的,例如与CoTaskMemAlloc。您的字符串不符合该要求。

  • 您可以更改Delphi代码以分配内存。
  • 您可以返回IntPtr并使用Marshal.PtrToStringAnsi手动编组。那么问题仍然是内存是否需要被释放,如果是这样的话。
  • 您可以返回COM BSTR,但这只适用于Delphi作为out参数而不是函数返回值。请参阅Why can a WideString not be used as a function return value for interop?
  • 您可以要求调用者分配内存并让被调用者填充它。

我无法确切地看到您的代码,但如果您返回PChar(s) s是一个局部变量,我不会感到惊讶。这意味着你将返回释放内存的地址。

这里的底线是将字符串(或实际上是数组或其他动态结构)从被调用者传递给调用者要比传递简单值类型复杂得多。您将需要重新考虑如何执行此操作。