调用ExtractIconExW多次致内存泄漏崩溃,原因是什么?
调用ExtractIconExW多次后内存崩溃的解决办法
核心问题
- 销毁句柄用错函数:图标句柄必须用
user32.dll中的DestroyIcon销毁,DeleteObject仅适用于GDI对象(如画笔、位图),对图标句柄无效,导致句柄持续泄漏,最终触发"内存不足"错误。 - 参数类型错误:
ExtractIconEx的图标索引要求为整数类型,你直接传递分割后的字符串s(1),会引发隐式转换异常或获取错误的图标。 - 句柄提前销毁:
CreateBitmapSourceFromHIcon不会接管图标句柄的生命周期,你在Finally块中直接销毁icon句柄,会导致返回的BitmapSource引用已失效的句柄,引发随机崩溃。
修复代码
1. 修正函数声明
替换DeleteObject为DestroyIcon的DllImport声明:
<DllImport("Shell32.dll", EntryPoint:="ExtractIconExW", CharSet:=CharSet.Unicode, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> Public Shared Function ExtractIconEx(sFile As String, iIndex As Integer, ByRef piLargeVersion As IntPtr, ByRef piSmallVersion As IntPtr, amountIcons As Integer) As Integer End Function <DllImport("user32.dll", SetLastError:=True)> Public Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean End Function
2. 修正ExtractIcon函数实现
Public Shared Function ExtractIcon(ref As String) As BitmapSource Dim s() As String = Split(ref, ",") Dim iconPath As String = s(0) ' 将索引转为整数,默认使用0 Dim iconIndex As Integer = If(s.Length > 1, Integer.Parse(s(1)), 0) Dim largeIcon As IntPtr = IntPtr.Zero Dim smallIcon As IntPtr = IntPtr.Zero Dim resultBitmap As BitmapSource = Nothing Try Functions.ExtractIconEx(iconPath, iconIndex, largeIcon, smallIcon, 1) If smallIcon <> IntPtr.Zero Then ' 通过GDI+中转,将图标数据复制到WPF BitmapSource,避免句柄依赖 Using gdiIcon As New System.Drawing.Icon(smallIcon) Using gdiBmp As System.Drawing.Bitmap = gdiIcon.ToBitmap() resultBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( gdiBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()) resultBitmap.Freeze() ' 冻结后提升性能,支持跨线程访问 End Using End Using ' 数据已复制,可安全销毁原图标句柄 Functions.DestroyIcon(smallIcon) End If Finally ' 无论是否成功,大图标句柄必须销毁 If largeIcon <> IntPtr.Zero Then Functions.DestroyIcon(largeIcon) End If End Try Return resultBitmap End Function
关键说明
- 通过
System.Drawing.Icon中转,可将图标数据复制到WPF的BitmapSource中,原句柄能立即销毁,彻底避免泄漏。 - 所有通过
ExtractIconEx获取的句柄(包括未使用的大图标句柄),都必须用DestroyIcon销毁。 - 冻结
BitmapSource可避免后续操作引发的线程安全问题,同时提升渲染性能。
内容的提问来源于stack exchange,提问作者miss programmer
相关产品推荐
相关产品推荐

