WPF 使用 SHGetFileInfo 造成内存泄漏问题

使用WPF自己做一个文件管理。其中,需要回去文件图标进行显示,使用win32接口进行,代码如下

/// <summary>
		/// 获取文件图标需要的结构体,作为出参,不需要初始化
		/// </summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct SHFILEINFO
		{
			public IntPtr hIcon;                                        //文件的图标句柄
			public int iIcon;                                              //文件图标的系统索引号
			public uint dwAttributes;                                //文件的属性值

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szDisplayName;                           //文件的显示名

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
			public string szTypeName;                               //文件的类型名
		}

		/// <summary>
		/// 使用win32程序,查看文件信息,主要是获取图标,包括文件图标,文件夹图标,驱动器图标
		/// </summary>
		/// <param name="strFilePath">文件路径</param>
		/// <param name="dwFileAttributes">文件属性,一般区分文件和文件夹</param>
		/// <param name="lpFileInfo">出参,保存图标等信息的结构体</param>
		/// <param name="cbFileInfoSize">结构体大小</param>
		/// <param name="uFlags">核心变量,通过不同的标志获取不同的信息</param>
		/// <returns></returns>
		[DllImport("shell32.dll", SetLastError = true)]
		public static extern int SHGetFileInfo(string strFilePath, uint dwFileAttributes, ref SHFILEINFO lpFileInfo, uint cbFileInfoSize, uint uFlags);

		[DllImport("user32.dll", SetLastError = true)]
		public static extern bool DestroyIcon(IntPtr hIcon);

		//获取图标
		private const uint SHGFI_ICON = 0x100;

		//大图标 32 x 32
		private const uint SHGFI_LARGEICON = 0x0;

		//小图标 16 x 16
		private const uint SHGFI_SMALLICON = 0x1;

		//使用use passed dwFileAttribute
		private const uint SHGFI_USEFILEATTRIBUTES = 0x10;

		private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
		private const uint FILE_ATTRIBUTE_DIRECTORY = 0x10;
		private const uint SHGFI_DISPLAYNAME = 0x200;
		private const uint SHGFI_SYSICONINDEX = 0x400;

		/// <summary>
		/// 自定义函数,获取文件的图标,可以指定大小图标,或者文件夹图标
		/// </summary>
		/// <param name="strFilePath">文件名</param>
		/// <param name="bSmallOrLarge">true 小图标  false 大图标</param>
		/// <param name="bDirectory">true  文件夹  false 文件</param>
		/// <returns></returns>
		public static ImageSource GetIcon(string strFilePath, bool bSmallOrLarge, bool bDirectory)
		{
			uint uFlag = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME;
			if (bSmallOrLarge)
				uFlag |= SHGFI_SMALLICON;

			uint uAttribute = FILE_ATTRIBUTE_NORMAL;
			if (bDirectory)
				uAttribute |= FILE_ATTRIBUTE_DIRECTORY;

			SHFILEINFO fileInfo = new SHFILEINFO();

			if (0 != SHGetFileInfo(strFilePath, uAttribute, ref fileInfo, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), uFlag))
			{
				if(fileInfo.hIcon != IntPtr.Zero)
				{
					BitmapSource bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(fileInfo.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
					return bmpSource;
				}
			}

			return null;
		}

然后运行界面,进行基本的文件显示和操作。

过一段时间之后,界面卡死了,查看任务管理器,发现 GDI 占用高达9999

网上搜了一下,原来需要对 SHGetFileInfo 获取到的图标进行释放。否则,会一直存在内存中,系统不会自己进行回收。

修改代码如下:

/// <summary>
		/// 自定义函数,获取文件的图标,可以指定大小图标,或者文件夹图标
		/// </summary>
		/// <param name="strFilePath">文件名</param>
		/// <param name="bSmallOrLarge">true 小图标  false 大图标</param>
		/// <param name="bDirectory">true  文件夹  false 文件</param>
		/// <returns></returns>
		public static ImageSource GetIcon(string strFilePath, bool bSmallOrLarge, bool bDirectory)
		{
			uint uFlag = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME;
			if (bSmallOrLarge)
				uFlag |= SHGFI_SMALLICON;

			uint uAttribute = FILE_ATTRIBUTE_NORMAL;
			if (bDirectory)
				uAttribute |= FILE_ATTRIBUTE_DIRECTORY;

			SHFILEINFO fileInfo = new SHFILEINFO();

			if (0 != SHGetFileInfo(strFilePath, uAttribute, ref fileInfo, (uint)Marshal.SizeOf(typeof(SHFILEINFO)), uFlag))
			{
				if(fileInfo.hIcon != IntPtr.Zero)
				{
					BitmapSource bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(fileInfo.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
					DestroyIcon(fileInfo.hIcon);
					return bmpSource;
				}
			}

			return null;
		}

注意,增加了这样一条:

DestroyIcon(fileInfo.hIcon);

然后,GDI保持在正常的水平,不会继续增长了。

点击这里可以下载文件管理代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值