2009-02-06 5 views
3

J'ai un problème dans une application Windows Forms avec Bitmap.Sauvegarde échouant lorsque je l'enregistre dans un MemoryStream. Le problème semble seulement se produire par intermittence sur une machine (jusqu'à présent) et la mauvaise nouvelle est sur un site client. Je ne peux pas déboguer sur la machine, mais j'ai une trace de pile qui réduit le problème à une seule ligne de code.GDI + exception sauvegarde un bitmap à un MemoryStream

Voici une version condensée de mon code:

byte[] ConvertPixelsToBytes() 
{ 
    // imagine a picture class that creates a 24 bbp image, and has 
    // a method to get an unmanaged pixel buffer. 
    // imagine it also has methods for getting the width, 
    // height, pitch 

    // I suppose this line could return a bad address, but 
    // I would have expected that the Bitmap constructor would have 
    // failed if it was 
    System.IntPtr pPixels = picture.GetPixelData(); 

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
      picture.width(), 
      picture.height(), 
      picture.pitch(), 
      System.Drawing.Imaging.PixelFormat.Format24bppRgb, 
      pPixels); 

    // This line doesn't actually free the memory, but it could be freed in a 
    // background thread 
    // (2) 
    picture.releasePixelData(pPixels); 

    System.IO.MemoryStream memStream = new System.IO.MemoryStream(); 
    try 
    { 
     // I don't see how this line could fail, but it does 
     // (3) 
     bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp); 
     return memStream.ToArray(); 
    } 
    catch(System.Runtime.InteropServices.ExternalException e) 
    { 
     // e.Message is the very helpful " A generic error occurred in GDI+." 
    } 
    finally 
    { 
     memStream.Dispose(); 
    } 
    return new byte[0]; 
} 

Toute idée de ce qui pourrait se passer? Je suis sûr que mon tampon de pixels est bon, il fonctionne toujours sur nos machines de développement/test et sur d'autres sites clients.

Mes réflexions sur les raisons possibles de l'échec sont

a. Le constructeur de bitmap ne copie pas les données de pixel, mais conserve une référence, et l'enregistrement échoue car la mémoire est libérée. Je ne trouve pas les documents MSDN claires sur ce point, mais je suppose que le bitmap copie les données de pixel plutôt que de supposer qu'il est verrouillé.

b. Les données de pixel ne sont pas valides et entraînent l'échec de la méthode Save. J'en doute car les données de mes pixels sont de 24 bits par pixel, donc pour autant que je sache, cela ne devrait pas être invalide.

c. Il y a un problème avec le framework .NET. J'apprécierais toute réflexion sur d'autres raisons possibles de défaillance afin que je puisse ajouter des contrôles supplémentaires et des informations de connexion à mon application afin que je puisse envoyer quelque chose sur le terrain.

+0

Une exception particulière? Ou est-ce une de ces exceptions "A Gerneic GDI + error has been"? –

+0

C'est l'une de ces exceptions "Generic GDI +". –

Répondre

5

Les docs MSDN pour ce constructeur Bitmap ne laissent aucun doute que ce soit:

Remarques L'appelant est responsable de l'attribution et de libérer le bloc de mémoire spécifiée par le paramètre scan0, cependant, la mémoire doit pas être libéré jusqu'à ce que le bitmap lié est libéré.

+0

Merci. Cela n'est en fait pas documenté dans la bibliothèque MSDN pour Visual Studio 2005 (la prochaine fois que je vais vérifier les documents en ligne également). –

+0

J'ai un problème qui est très similaire à cela, en utilisant également bmp.Save (memStream, ...etc Bien qu'il semble vrai que la documentation mentionne ce que vous dites, il semble se référer à un flux de mémoire utilisé dans le constructeur d'un bmp - maintenant cela a du sens, mais ce qui est plus difficile à accepter est un flux de mémoire que le bitmap est sauvé à doit être tenu à jour - J'ai écrit à un png, Il ne se passe que mal sur une machine de production et le problème est intermittent, est seulement résolu si le pool d'applications est recyclé. A travaillé 10 ans sans problème précédemment. Mais merci pour info! – Cato

2

Avez-vous essayé de déplacer

picture.releasePixelData(pPixels); 

à

finally 
    { 
     memStream.Dispose(); 
     picture.releasePixelData(pPixels); 
    } 

ça sonne vraiment comme un problème de filetage (d'autant plus que vous déclarez que le releasePixelData pourrait se produire sur un fil d'arrière-plan). Les problèmes de threading sont toujours ceux qui n'arrivent que sur une machine, et ils sont toujours sur la machine des clients (probablement parce qu'ils n'ont que 256 Mo de mémoire ou quelque chose de ridicule et que le garbage collector est en avance). et votre machine de développement est dual core ou quelque chose).

Questions connexes