Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: bybaal en 9 Abril 2023, 08:22 am



Título: Error Genérico en GDI+
Publicado por: bybaal en 9 Abril 2023, 08:22 am
Hola tengo esta función para convertir un bitmap a icono y en algunas ocasiones ocurre la excepción 'Error Genérico en GDI+' en la última línea, alguna idea de que pueda estar pasando

Código:
    Public Function ToIcon(Image As Image,
                                  Width As Integer,
                                  Height As Integer,
                                  Optional MakeTransparent As Boolean = False,
                                  Optional Transparent As Color = Nothing) As Icon
        ToIcon = Nothing
        If IsNothing(Transparent) Then Transparent = Color.White
        Dim thumb As Bitmap = CType(Image.GetThumbnailImage(Width, Height, Nothing, IntPtr.Zero), Bitmap)
        If MakeTransparent Then thumb.MakeTransparent(Transparent)
        ToIcon = Icon.FromHandle(thumb.GetHicon())
    End Function


Título: Re: Error Genérico en GDI+
Publicado por: LlopoRobot en 9 Abril 2023, 17:45 pm
La excepción 'Error Genérico en GDI+' suele ocurrir cuando hay un problema con los recursos de GDI+ del sistema. Es posible que se esté produciendo una fuga de memoria o que se esté utilizando demasiada memoria.

Para solucionar este problema, puedes intentar liberar los recursos de memoria de GDI+ llamando al método Dispose en la imagen de vista previa y en el objeto Bitmap, así:

Código
  1. Public Function ToIcon(Image As Image,
  2.                        Width As Integer,
  3.                        Height As Integer,
  4.                        Optional MakeTransparent As Boolean = False,
  5.                        Optional Transparent As Color = Nothing) As Icon
  6.    ToIcon = Nothing
  7.    If IsNothing(Transparent) Then Transparent = Color.White
  8.    Dim thumb As Bitmap = CType(Image.GetThumbnailImage(Width, Height, Nothing, IntPtr.Zero), Bitmap)
  9.    If MakeTransparent Then thumb.MakeTransparent(Transparent)
  10.    ToIcon = Icon.FromHandle(thumb.GetHicon())
  11.    thumb.Dispose()
  12.    Image.Dispose()
  13. End Function

Además, asegúrate de que la imagen y el objeto Bitmap se estén utilizando dentro de un bloque Using o se estén liberando adecuadamente en otro lugar del código.


Título: Re: Error Genérico en GDI+
Publicado por: bybaal en 10 Abril 2023, 20:28 pm
Ya lo agregué, pero sigue el problema, por eso aquí comparto todo el código para que se vea mejor cual puede ser el problema

Código
  1. Public Class Form1
  2.    Private WithEvents tmrRefresh As New Timer With {.Enabled = True, .Interval = 1}
  3.  
  4.    Private Sub tmrRefresh_Tick(sender As Object, e As EventArgs) Handles tmrRefresh.Tick
  5.        Dim gr As Graphics
  6.        Dim bmp As Bitmap = My.Resources.white
  7.        Dim br As New SolidBrush(Color.Black)
  8.        Dim free As String = AutoScaleSize(My.Computer.Info.AvailablePhysicalMemory, 2, False)
  9.        Dim x() As String
  10.        Dim por As Integer
  11.        Dim colBar As Color
  12.  
  13.        Text = free
  14.        x = Split(free)
  15.        free = x(0)
  16.        x = Split(free, ",")
  17.        If Len(x(0)) = 1 Then x(0) = $"0{x(0)}"
  18.        If Len(x(1)) = 1 Then x(1) = $"0{x(1)}"
  19.  
  20.        gr = Graphics.FromImage(bmp)
  21.        gr.DrawString($"{x(0)},", New Font("Arial", 12, FontStyle.Bold), br, New PointF(0, 0))
  22.        gr.DrawString(x(1), New Font("Arial", 12, FontStyle.Bold), br, New PointF(0, 14))
  23.  
  24.        por = Porciento(My.Computer.Info.AvailablePhysicalMemory,
  25.                        My.Computer.Info.TotalPhysicalMemory)
  26.        Select Case por
  27.            Case Is >= 75 : colBar = Color.Green
  28.            Case Is >= 50 : colBar = Color.Yellow
  29.            Case Is >= 25 : colBar = Color.Orange
  30.            Case Is >= 0 : colBar = Color.Red
  31.        End Select
  32.        gr.DrawLine(New Pen(colBar, 5), 28, 2, 28, 30)
  33.  
  34.        Icon = ToIcon(bmp, 32, 32)
  35.  
  36.        bmp.Dispose()
  37.        gr.Dispose()
  38.        br.Dispose()
  39.  
  40.    End Sub
  41.  
  42. End Class
  43.  
  44. Module modExtras
  45.  
  46.    Public Function Porciento(Parte As ULong,
  47.                              Total As ULong,
  48.                              Optional Round As Boolean = False,
  49.                              Optional Decimals As Integer = 0) As Double
  50.        Porciento = 0
  51.        Try
  52.            Porciento = Parte * 100 / Total
  53.            If Round Then Porciento = Math.Round(Porciento, Decimals)
  54.        Catch ex As Exception
  55.        End Try
  56.    End Function
  57.  
  58.    Public Function ToIcon(Image As Image,
  59.                           Width As Integer,
  60.                           Height As Integer,
  61.                           Optional MakeTransparent As Boolean = False,
  62.                           Optional Transparent As Color = Nothing) As Icon
  63.        ToIcon = Nothing
  64.        'Try
  65.        If IsNothing(Transparent) Then Transparent = Color.White
  66.        Dim thumb As Bitmap = CType(Image.GetThumbnailImage(Width, Height, Nothing, IntPtr.Zero), Bitmap)
  67.        If MakeTransparent Then thumb.MakeTransparent(Transparent)
  68.        ToIcon = Icon.FromHandle(thumb.GetHicon())
  69.        thumb.Dispose()
  70.        Image.Dispose()
  71.        'Catch ex As Exception
  72.        'End Try
  73.    End Function
  74.  
  75.    Public Function AutoScaleSize(Bytes As Decimal,
  76.                                  Optional Decimals As Integer = 2,
  77.                                  Optional FullName As Boolean = False,
  78.                                  Optional BaseMil As Boolean = False) As String
  79.        AutoScaleSize = ""
  80.        Try
  81.            Dim C As Integer
  82.            Dim b As Decimal = Bytes
  83.            Dim Div As Integer
  84.  
  85.            If BaseMil Then Div = 1000 Else Div = 1024
  86.            Do While b >= Div
  87.                b /= Div
  88.                C += 1
  89.            Loop
  90.            b = Math.Round(b, Decimals)
  91.            Select Case C
  92.                Case 0 : If FullName Then Return b & " Bytes" Else Return b & " B"
  93.                Case 1 : If FullName Then Return b & " KiloBytes" Else Return b & " KB"
  94.                Case 2 : If FullName Then Return b & " MegaBytes" Else Return b & " MB"
  95.                Case 3 : If FullName Then Return b & " GigaBytes" Else Return b & " GB"
  96.                Case 4 : If FullName Then Return b & " TeraBytes" Else Return b & " TB"
  97.                Case 5 : If FullName Then Return b & " PetaBytes" Else Return b & " PB"
  98.                Case 6 : If FullName Then Return b & " ExaBytes" Else Return b & " EB"
  99.                Case 7 : If FullName Then Return b & " ZettaBytes" Else Return b & " ZB"
  100.                Case 8 : If FullName Then Return b & " YottaBytes" Else Return b & " YB"
  101.                Case Else : If FullName Then Return Bytes & " Bytes" Else Return Bytes & " B"
  102.            End Select
  103.        Catch ex As Exception
  104.        End Try
  105.    End Function
  106.  
  107. End Module
  108.  
  109.  


Título: Re: Error Genérico en GDI+
Publicado por: Elektro Enjuto en 30 Agosto 2023, 19:23 pm
El tamaño y las características de la imagen de recurso "white" son desconocidos, así que no soy capaz de reproducir el problema que describes.

De todas formas, estás añadiendo una carga altísima y totalmente innecesaria al utilizar procedimientos de dibujado manual, generando una lentitud de respuesta en tu aplicación, y por culpa de un intervalo de temporizador tan reducido, todo para hacer cosas que son facilmente accesibles mediante las propiedades del Form...

Primeramente, ¿por qué asignas la imagen de icono más de una única vez?. En cada iteración del temporizador vuelves a pasar por todo el procedimiento de copia de imagen y resscalado solo para volver a reasignar la misma imagen una y otra vez, sin descanso.

Lo mismo haces al dibujar texto en la barra de título del form, cosa que puedes asignar mediante la propiedad Form.Text, y eso siempre estará mucho más optimizado que cualquier procedimiento casero de dibujado como el que estás utilizando.

Por último aquí te dejo una versión simplificada de la función ToIcon, sin recurrir a la función GetThumbnailImage para no deteriorar la calidad inicial pre-obtención de icono:

Código
  1.    <DebuggerStepThrough>
  2. Public Function ToIcon(image As Image, size As Size,
  3.                       Optional makeTransparent As Boolean = False,
  4.                       Optional transparentColor As Color = Nothing) As Icon
  5.  
  6.    Using clone As New Bitmap(image, size)
  7.        If makeTransparent AndAlso (transparentColor <> Color.Empty) Then
  8.            clone.MakeTransparent(transparentColor)
  9.        End If
  10.  
  11.        Return Icon.FromHandle(clone.GetHicon())
  12.    End Using
  13.  
  14. End Function

Saludos.