吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 602|回复: 7
收起左侧

[求助] 一个右键菜单引发的崩溃

[复制链接]
gufengaoyue 发表于 2024-5-22 11:05
本帖最后由 gufengaoyue 于 2024-5-22 14:15 编辑

我在VB.NET中,用sharpshell做了一个右键菜单的类库。
其中用System.Drawing中的image等来处理图标作为右键菜单的图标来显示。
但经过测试,大概使用了72次后(右键点击72次左右),菜单就崩溃了(右键菜单变黑变窄,没有文字图标,只有纯黑或纯白)。
调试时,在崩溃的时候出现以下提示,崩溃后,原本正常工作的System.Drawing下的类如Image,Icon,等等,都变成nothing(失去了System.Drawing引用):

“explorer.exe”(CLR v4.0.30319: DefaultDomain): 已加载“C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Drawing.resources\v4.0_4.0.0.0_zh-Hans_b03f5f7f11d50a3a\System.Drawing.resources.dll”。模块已生成,不包含符号。
引发的异常:“System.ArgumentException”(位于 System.Drawing.dll 中)
**icon** 是 Nothing。
加载图标 ,我用过了异步、同步,或者缓存等方式,但都不能改变崩溃的结果。
[Visual Basic .NET] 纯文本查看 复制代码
 
subMenu.Image = Image.FromFile(img_path)
subMenu.Image = Await IconManager.LoadIconAsync(img_path)


这时候,只有重启Explorer才恢复正常。但再经过72次后,又会崩溃。(似乎C#也这样)
请教大佬,这是什么原因?是System.Drawing本身的bug,还是类库或Explorer本身的限制?
重要的一点:如果不使用图标,就是不用System.Drawing,Explorer就不会崩溃。
恳请知道的大佬不吝赐教,万分感激!

image.png
image.png


image.png

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

刺心 发表于 2024-5-22 17:35
本帖最后由 刺心 于 2024-5-22 17:39 编辑

出现这个问题可能是由于资源泄漏,特别是在使用 System.Drawing 和处理图标时。每次加载图像时,如果没有正确释放资源,可能会导致内存和资源的耗尽,从而导致崩溃。以下是一些可能的解决方法和优化建议:

1. 确保正确释放资源
确保在使用完图像和图标后,调用 Dispose 方法释放资源。例如:
[Visual Basic .NET] 纯文本查看 复制代码
Dim img As Image = Nothing
Try
    img = Image.FromFile(img_path)
    subMenu.Image = img
Finally
    If img IsNot Nothing Then
        img.Dispose()
    End If
End Try


2. 使用 Using 语句
Using 语句可以自动处理资源的释放:
[Visual Basic .NET] 纯文本查看 复制代码
Using img As Image = Image.FromFile(img_path)
    subMenu.Image = img
End Using

对于异步方法,也应确保正确释放资源:
[Visual Basic .NET] 纯文本查看 复制代码
Using icon As Icon = Await IconManager.LoadIconAsync(img_path)
    Using bmp As Bitmap = icon.ToBitmap()
        subMenu.Image = CType(bmp.Clone(), Image)
    End Using
End Using


3. 缓存图标
如果图标是固定的,可以考虑将图标缓存起来,而不是每次都重新加载。这可以减少资源的使用频率:
[Visual Basic .NET] 纯文本查看 复制代码
Dim iconCache As New Dictionary(Of String, Image)

Function GetIcon(img_path As String) As Image
    If Not iconCache.ContainsKey(img_path) Then
        iconCache(img_path) = Image.FromFile(img_path)
    End If
    Return iconCache(img_path)
End Function

subMenu.Image = GetIcon(img_path)

4. 检查图像格式和大小
确保图像格式和大小合适,以避免不必要的内存占用。
5. 监控资源使用
使用工具监控 Explorer 的内存和资源使用情况,确保找出确切的资源泄漏点。例如,使用 Process Explorer 或者内存分析工具。
6. 处理图像转换
在处理图像转换时,也要注意资源释放:
[Visual Basic .NET] 纯文本查看 复制代码
Using icon As Icon = Await IconManager.LoadIconAsync(img_path)
    Using bmp As Bitmap = icon.ToBitmap()
        subMenu.Image = CType(bmp.Clone(), Image)
    End Using
End Using


7. 避免频繁加载和释放
如果可能,减少频繁的加载和释放操作。例如,保持菜单项在整个应用程序的生命周期中使用相同的图标。

通过以上方法,你应该能够减少资源泄漏的风险,避免 Explorer 因资源耗尽而崩溃。如果问题仍然存在,建议进一步检查 System.Drawing 或相关库的使用方式,或者考虑使用其他图形库,如 System.Drawing.Common 或 SkiaSharp,以提高稳定性和性能。

8.使用 System.Drawing.Common
System.Drawing.Common 是 .NET Core 和 .NET 5+ 的跨平台版本,但其使用方法与原来的 System.Drawing 类似。
安装
首先,通过 NuGet 安装 System.Drawing.Common:
[Shell] 纯文本查看 复制代码
Install-Package System.Drawing.Common


使用 Using 语句来确保资源的释放:
[Visual Basic .NET] 纯文本查看 复制代码
Imports System.Drawing

Public Sub SetMenuImage(subMenu As ToolStripMenuItem, imgPath As String)
    Using img As Image = Image.FromFile(imgPath)
        subMenu.Image = CType(img.Clone(), Image)
    End Using
End Sub


对于异步方法:
[Visual Basic .NET] 纯文本查看 复制代码
Imports System.Drawing

Public Async Function LoadIconAsync(imgPath As String) As Task(Of Image)
    Return Await Task.Run(Function()
                              Using icon As New Icon(imgPath)
                                  Return CType(icon.ToBitmap().Clone(), Image)
                              End Using
                          End Function)
End Function

Public Async Sub SetMenuImageAsync(subMenu As ToolStripMenuItem, imgPath As String)
    Using img As Image = Await LoadIconAsync(imgPath)
        subMenu.Image = img
    End Using
End Sub



使用 SkiaSharp
SkiaSharp 是一个高性能的跨平台图形库。
安装
首先,通过 NuGet 安装 SkiaSharp:
[Shell] 纯文本查看 复制代码
Install-Package SkiaSharp


使用 SkiaSharp 加载和处理图像:
[Visual Basic .NET] 纯文本查看 复制代码
Imports SkiaSharp

Public Sub SetMenuImage(subMenu As ToolStripMenuItem, imgPath As String)
    Using inputStream As New SKFileStream(imgPath)
        Using skBitmap As SKBitmap = SKBitmap.Decode(inputStream)
            Using skImage As SKImage = SKImage.FromBitmap(skBitmap)
                Using skData As SKData = skImage.Encode()
                    Using ms As New MemoryStream(skData.ToArray())
                        subMenu.Image = Image.FromStream(ms)
                    End Using
                End Using
            End Using
        End Using
    End Using
End Sub


对于异步方法:
[Visual Basic .NET] 纯文本查看 复制代码
Imports SkiaSharp

Public Async Function LoadImageAsync(imgPath As String) As Task(Of Image)
    Return Await Task.Run(Function()
                              Using inputStream As New SKFileStream(imgPath)
                                  Using skBitmap As SKBitmap = SKBitmap.Decode(inputStream)
                                      Using skImage As SKImage = SKImage.FromBitmap(skBitmap)
                                          Using skData As SKData = skImage.Encode()
                                              Using ms As New MemoryStream(skData.ToArray())
                                                  Return Image.FromStream(ms)
                                              End Using
                                          End Using
                                      End Using
                                  End Using
                              End Using
                          End Function)
End Function

Public Async Sub SetMenuImageAsync(subMenu As ToolStripMenuItem, imgPath As String)
    Using img As Image = Await LoadImageAsync(imgPath)
        subMenu.Image = img
    End Using
End Sub

 楼主| gufengaoyue 发表于 2024-5-22 18:03
刺心 发表于 2024-5-22 17:35
出现这个问题可能是由于资源泄漏,特别是在使用 System.Drawing 和处理图标时。每次加载图像时,如果没有正 ...

非常感谢您的细心回复!
试过using和dispose,但无法加载图标,感觉可能释放掉以后就不能加载。
异步和缓存也都试过了,都不行。
感觉就是System.Drawing的毛病,只要不用SystemDrawing就没事。
没试过其他库,找个机会再试试。
无敌小儿 发表于 2024-5-23 09:13
 楼主| gufengaoyue 发表于 2024-5-23 10:07
无敌小儿 发表于 2024-5-23 09:13
右键菜单不错,可以讲下怎么制作的吗

用的sharpshell做的,你可以参考下官网,上面有范例
https://github.com/dwmkerr/sharpshell
刺心 发表于 2024-5-23 11:34
gufengaoyue 发表于 2024-5-22 18:03
非常感谢您的细心回复!
试过using和dispose,但无法加载图标,感觉可能释放掉以后就不能加载。
异步和 ...

你可以看看其他人写的试试。或者用一下其他的库
 楼主| gufengaoyue 发表于 2024-5-23 11:40
刺心 发表于 2024-5-23 11:34
你可以看看其他人写的试试。或者用一下其他的库

之前也有人写过这样的右键菜单,我试了一下,同样会崩溃。
菜单文字和图标没了,变黑框了
刺心 发表于 2024-5-31 17:14
gufengaoyue 发表于 2024-5-23 11:40
之前也有人写过这样的右键菜单,我试了一下,同样会崩溃。
菜单文字和图标没了,变黑框了

学习到了。谢谢大佬
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-12 17:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表