2009-11-20 7 views
10

J'ai un objet Graphics global créé à partir d'un Panel. À intervalles réguliers, une image est extraite du disque et dessinée dans le panneau à l'aide de Graphics.DrawImage(). Il fonctionne très bien pour quelques itérations puis je commence à l'exception utile suivante:Lors du dessin d'une image: System.Runtime.InteropServices.ExternalException: Une erreur générique s'est produite dans GDI

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+. 
at System.Drawing.Graphics.CheckErrorStatus(Int32 status) 
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y) 
at System.Drawing.Graphics.DrawImage(Image image, Point point) 

J'Exclue des fuites de mémoire que je dispose de l'objet d'image quand je suis fait avec elle. Je sais que les images ne sont pas corrompues et peuvent être lues correctement car le programme s'exécute bien pendant un moment avant que le panneau arrête de montrer.

J'ai rencontré le même problème lors de l'utilisation d'un PictureBox mais cette fois au moins j'ai eu une erreur au lieu de rien.

J'ai vérifié les objets GDI et les objets USER dans le gestionnaire de tâches, mais ils sont toujours autour de 65 objets utilisateur et 165 objets GDI lorsque l'application fonctionne et quand elle ne fonctionne pas.

Je dois aller au fond des choses dès que possible et ce n'est pas comme si je pouvais coller des points d'arrêt dans les bibliothèques du système .NET et voir exactement où l'exécution échoue.

Merci d'avance.

EDIT: Voici le code d'affichage:

private void DrawImage(Image image) 
{ 
    Point leftCorner = new Point((this.Bounds.Width/2) - (image.Width/2), (this.Bounds.Height/2) - (image.Height/2)); 
    _graphics.DrawImage(image, leftCorner); 
} 

le code de chargement de l'image:

private void LoadImage(string filename, ref Image image) 
{ 
    MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword); 

    image = Image.FromStream(memoryStream); 

    memoryStream.Close(); 
    memoryStream.Dispose(); 
    memoryStream = null; 
} 

_Image est globale et sa référence est mise à jour LoadImage. Ils sont transmis en tant que paramètres car je veux changer les références globales à partir d'aussi peu d'endroits que possible et garder les autres méthodes autonomes. _graphics est aussi global.

J'ai aussi un contrôle webBrowser pour les sites web et je montre une image ou un site web en même temps. quand il y a de temps pour afficher une image, le code suivant exécute:

webBrowser.Visible = false; 
panel.Visible = true; 
DrawImage(_image) 
_image.Dispose(); 
_image = null; 

_Image fait référence à une image pré-chargé.

Espérons que cela aide.

Répondre

14

Votre problème est similaire à ce que je pensais, mais pas tout à fait . Lorsque vous chargez l'image, vous la chargez à partir d'un MemoryStream. Vous devez garder le flux ouvert pour la durée de vie de l'image, voir MSDN Image.FromStream.

Vous devez conserver le flux ouvert pendant la durée de vie de l'image.

La solution est de faire une copie de votre image dans la fonction FromImage:

private void LoadImage(string filename, ref Image image) 
{ 
    using (MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword)) 
    { 
     using (tmpImage = Image.FromStream(memoryStream)) 
     { 
     image = new Bitmap(tmpImage); 
     } 
    } 

} 

similaires au problème de Éliminez je l'ai mentionné, l'image semble fonctionner et ne pas au hasard lorsque le flux sous-jacent est la poubelle collectée.

+0

Je vais essayer, merci. N'avons-nous pas besoin de disposer explicitement tmpImage? L'élimination de memoryStream va-t-elle également éliminer l'image sous-jacente? – Michali

+0

Oui, vous devez disposer de tmpImage explicitement, bien que la disposition du memoryStream récupérera la plupart des données sous-jacentes. J'ai changé la réponse pour le montrer. –

+0

Merci. Cela semble l'avoir résolu. – Michali

2

Sans un peu plus de code, il ne suffit pas de diagnostiquer correctement ici, cependant, une chose à regarder est que vous avez peut-être disposé sur l'image de votre dessin avec un peu plus tôt et c'est seulement après le garbage collector s'exécute que votre code échoue. Utilisez-vous des images clonées n'importe où? Une chose que j'ai été surpris d'apprendre est que si vous faites un clone d'une image, vous ne clonez pas le bitmap sous-jacent sur lequel repose l'image, seulement la structure de l'image, pour créer une copie correcte d'une image que vous devez créer. nouvelle image:

var newImage = new Bitmap(img) 

comme

var newImage = oldImg.Clone(); 
oldImg.Dispose(); 
... 
gr.DrawImage(newImage, new Rectangle(0,0,newImage.Width,newImage.Height); 

travaillera pendant un certain temps, mais échouer à un moment donné au hasard ...

+0

J'ai mis un peu plus de code maintenant. J'espère que cela fera la lumière. – Michali

+0

Juste pour garder les choses claires, j'ai posté la réponse à votre problème ci-dessous. –

Questions connexes