我已经导入了 dll。所有其他部分都有效,但导入方法的字符串返回值给出了这个:
Unhandled exception at 0x7748EA5F (ntdll.dll) in ***.exe: 0xC0000374: A heap has been corrupted (parameters: 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;
我对整数、 double 、 bool 值和 dll 中的所有其他东西都有相同类型的代码,没有错误。所以我认为它会造成某种溢出或错误的内存分配大小。
注意:如果我创建控制台应用程序,它只会失败,不会因错误而中断,如果我在没有调试器 ( ctrl+f5 ) 的情况下运行控制台,它会工作,但仍然没有错误。当我从表单应用程序调用它时生成堆错误。
长话短说;此代码有效,但它显示堆错误,同时返回 int、bool 等完美无缺。
最佳答案
当您返回一个字符串作为 p/invoke 函数的函数返回值时,编码器负责释放该内存。它假定内存是在 COM 堆上分配的,例如使用 CoTaskMemAlloc
。您的字符串不符合该要求。
- 您可以更改 Delphi 代码以那样分配内存。
- 您可以返回
IntPtr
并使用Marshal.PtrToStringAnsi
手动编码(marshal)。问题仍然是是否需要释放内存,如果需要如何释放。 - 您可以返回一个 COM BSTR,但这仅适用于 Delphi 作为输出参数而不是函数返回值。参见 Why can a WideString not be used as a function return value for interop?
- 您可以要求调用者分配内存并让被调用者填充它。
我不能肯定地看到你的代码,但如果你返回 PChar(s)
我不会感到惊讶,其中 s
是一个局部变量.这意味着您将返回已释放内存的地址。
这里的底线是,从被调用方到调用方传递字符串(或者实际上是数组或其他动态结构)比传递简单的值类型要复杂得多。您将需要重新考虑如何执行此操作。
关于c# - 堆已损坏。 C# dllimport、delphi PChar返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30349296/