我需要做这样的事情:
TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf<TEXTMETRIC>(tm));
Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);
Marshal.FreeHGlobal(ptr);
}
或者一旦函数退出,是否会自动清除分配的记忆? 我想(从我读过的)是后者,但我不确定!
任何解释都表示赞赏!
答案 0 :(得分:5)
Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);
在这里使用 true 是非常错误的。您使用AllocHGlobal()分配的内存未已初始化并包含随机字节。它 not 包含在被方法覆盖之前需要释放的结构的先前版本。
这可能在技术上导致非常难以诊断随机崩溃,具体取决于随机字节值。你侥幸成功,因为TEXTMETRIC不包含任何需要清理的成员。 FreeHGlobal()调用就足够了,不需要Marshal.DestroyStructure(),你应该将它放在finally块中,这样它就是异常安全的。哪个回答你的问题。
要完成,只有在结构包含BSTR,SAFEARRAY或COM接口指针时才需要清理。具有显式释放调用且在结构声明中需要[MarshalAs]属性的资源。当你使用pinvoke时,这种情况非常罕见。使用COM互操作时并不罕见,也使用了引擎盖下的StructureToPtr(),但CLR会自动进行调用。
答案 1 :(得分:4)
您调用的函数GetTextMetrics
期望调用者为结构分配和释放内存。如果您使用AllocHGlobal
进行分配,则必须使用FreeHGlobal
取消分配。
然而,这一切都是不必要的。您在声明tm
时分配结构。没有什么比这更需要了。从不致电FreeHGlobal
,无需致电AllocHGlobal
。
TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
}
避免手动分配还可以避免对其他答案所描述的StructureToPtr
进行断断续续的呼叫或任何呼叫。
答案 2 :(得分:2)
不,如果您使用AllocHGlobal
分配内存,必须自行释放内存。否则记忆将被泄露。
指向新分配的内存的指针。此内存必须才能释放 使用Marshal.FreeHGlobal方法。
答案 3 :(得分:1)
如果您手动分配非托管内存(并且您正在这样做),则需要手动释放它。添加finally
块以确保没有异常会干扰释放内存。
但是,您的示例没有多大意义,因为您将tm
复制到您从未使用过的内存块。