短版:
将句柄从globalalloc(gmem_moveable,size)传递到marshal.ptrtostructure()和marshal.freehglobal()会导致内存损坏吗?
长版本:
我正在使用Windows全局内存分配在Delphi和C应用程序之间来回传递数据结构(Delphi的事实对这个问题并不重要,因为它只是Win32 API调用)。
在Delphi方面,我传入一个记录,它分配空间,锁定内存,将结构复制到内存中,然后解锁内存:
function MarshalRec(SourceRec: TInteropItemRec): THandle;
var
Size: integer;
Buffer: Pointer;
begin
Size := sizeof(SourceRec);
result := GlobalAlloc(GMEM_MOVEABLE and GMEM_ZEROINIT, Size);
Buffer := GlobalLock(result);
try
CopyMemory(Buffer, @SourceRec, Size);
finally
GlobalUnlock(result);
end;
end;
在C端,它将thandle(基本上是一个无符号int)放入intptr,并使用marshal.ptrtostructure将数据复制到C结构中:
public void FromMemory(IntPtr Source)
{
Marshal.PtrToStructure(Source, this);
Marshal.FreeHGlobal(Source);
}
我遇到的问题很少(对我来说是6个月内的4次),整个应用程序都会停机(这个应用程序遇到错误,必须关闭)。如果我尝试在Visual Studio中暂停执行,我会得到“发生了致命错误,需要终止调试”。有关详细信息,请参阅Microsoft帮助和支持网站。hresult=0x80131c08。'
不管怎样,我们设法得到了一些它发生的日志,在这两种情况下,它显示了最近对上面的“marshalrec”函数的调用,一些其他函数调用,然后在delphi线程的事件循环上处理Windows消息(是的,它有自己的线程和事件循环来处理时间敏感的设备驱动程序)。
因此,我的怀疑落在了GMEM可移动的标志上。我在Marshal类中找不到执行globalLock和globalUnlock操作的任何内容,因此我假设它是由ptrtoStructure()内部处理的。
ptrtoStructure是否正确处理句柄,或者它是否需要从globalLock()获取实际指针?在非常罕见的情况下,Windows是否可能会移动我分配的内存,这意味着我需要调用globallock()来获取要传入的实际指针?FreehGlobal实际上正在释放一些它不应该释放的东西,这会在下一次访问资源时导致整个应用程序的关闭?
如果是这样的话,将移动的gmem_改为固定的gmem_是否应该防止这种情况再次发生?还是需要dllimport globallock()和globalunlock()?
我很想盲目地做出这些改变,但是考虑到这个问题的不可复制性,在它再次发生之前,无法判断它是否被修复。所以我在寻找关于这段代码是否会导致我看到的症状的反馈,或者如果我需要开始想出其他的理论。