2014-03-04 10 views
5

(Bitte beachten Sie die Bearbeitung auf dem Boden der Frage, ob Sie die ganze Geschichte nicht lesen will.)Warum wird PictureBox.Load auf einigen Systemen gesperrt?

Hallo,

Ich bin neu in Stackoverflow. Versteh mich nicht falsch, ich benutze es ziemlich oft. Aber bis jetzt habe ich nie etwas gepostet. Das liegt daran, dass ich nichts Neues/Nützliches zu sagen hatte und mein Englisch nicht so gut ist. Das erste (vielleicht) hat sich geändert, das andere nicht.

Ich stieß vor kurzem auf ein Problem mit dem Windows 7-System eines Kunden. Ich habe eine C# .Net 4.0 Windows Forms-Anwendung über ClickOnce ausgeliefert. Im Grunde erstellt eine Anwendung eine Bitmap-Datei und zeigt sie dem Benutzer an. Wenn die Bitmap vor der Erstellung vorhanden ist, wird die vorhandene Datei zuerst gelöscht. Danach wird die neue Datei erstellt und von einer PictureBox geladen.

Beim System des Kunden ist folgendes passiert: Nach dem Start der Anwendung ist die erste Erstellung erfolgreich - die zweite und alle folgenden nicht. Die Datei kann nicht gelöscht werden, da ein Prozess sie blockiert. Dieser Prozess ist die Anwendung selbst.

System.IO.IOException: Der Prozess kann nicht auf die Datei "Dateiname" zugreifen, da sie von einem anderen Prozess verwendet wird.

Nun, das ist natürlich nichts Ungewöhnliches. Die Sache ist, ich habe die Anwendung auf mehreren Systemen getestet. Keine zeigte diese Ausnahme. Und bis jetzt kann ich keinen Codefehler sehen.

Also schaute ich ein bisschen näher auf das System des Kunden: Der einzige Unterschied, den ich finden konnte, ist, dass sie den Benutzerordner änderten, so dass sie nicht auf der Windows-Partition, aber auf einem anderen liegen \ Benutzer -> D: \ Benutzer). Ich habe im Internet nach einer Anleitung gesucht und dasselbe auf einem meiner Testsysteme gemacht. Zu meiner Überraschung habe ich dieselbe Ausnahme, als ich meine Anwendung darauf ausgeführt habe.

Damit könnte ich meinen Code ändern, so dass die Ausnahme nicht mehr auftritt. Aber ich verstehe nicht, warum das so ist. Vielleicht stimmt also etwas mit meinem Code nicht und der Fehler zeigt sich gerade unter diesen besonderen Umständen. Oder vielleicht ist der Code in Ordnung und der Grund liegt woanders. Ich habe nur gehofft, dass du mir vielleicht helfen kannst.

Also hier ist ein Code, den ich zusammengestellt habe, der das gleiche Verhalten zeigt. Ich habe 3 Buttons, einen OpenFileDialog und eine PictureBox auf einem Formular verwendet. Zuerst muss eine Bilddatei ausgewählt werden. Durch Drücken einer der beiden verbleibenden Tasten wird es in den Hauptordner der Anwendung kopiert. Nach dem Kopieren wird es von der PictureBox angezeigt. Übrigens scheint es egal zu sein, ob es sich um eine ClickOnce-Anwendung oder um eine "normale" Anwendung handelt.

String m_FileName; 

private void btnChooseFile_Click(object sender, EventArgs e) { 
    if(openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // If file was chosen, set file name for later use and activate buttons. 
     m_FileName = "Test" + Path.GetExtension(openFileDialog1.FileName); 
    } 
} 

private void button1_Click(object sender, EventArgs e) { 

    // This is not working. 
    if(this.pictureBox1.Image != null) { 
     //Image img = this.pictureBox1.Image; // I was not sure, if maybe the pictureBox somehow prevents the disposing of the image, as long as it's assigned to it. 
     //this.pictureBox1.ImageLocation = null; // So I set them null, both the image and the image location. 
     //this.pictureBox1.Image = null; 
     //img.Dispose(); // Then I disposed the image. 

     this.pictureBox1.Image.Dispose(); // The short version. It is not working either way. 
     this.pictureBox1.Image = null; 
    } 
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); // But still this is where the Exception occurs. 
    this.pictureBox1.Load(m_FileName); 
} 

private void button2_Click(object sender, EventArgs e) { 

    //This is working. 
    if(this.pictureBox1.Image != null) { 
     //Image img = this.pictureBox1.Image; 
     //this.pictureBox1.Image = null; 
     //img.Dispose(); 

     this.pictureBox1.Image.Dispose(); 
     this.pictureBox1.Image = null; 
    } 
    (new FileInfo(openFileDialog1.FileName)).CopyTo(m_FileName, true); 
    pictureBox1.Image = Image.FromFile(m_FileName); 
} 

Was jetzt passiert, ist die folgende: Wenn ich die Anwendung und klicken Sie auf button1 zweimal starten, werde ich die Ausnahme erhalten (auf dem zweiten Klick). Wenn ich es starte und zweimal auf Button2 klicke, werde ich nicht. Wenn ich die Anwendung starte und zuerst auf buttons1 und dann auf button2 klicke, erhalte ich die Ausnahme. So blockiert die Picture.Load-Funktion die Datei irgendwie, auch wenn ich sie entsorge. Wenn ich im Internet suchte, fand ich einen Artikel von Microsoft: http://support.microsoft.com/kb/309482/en-us. Aber es trifft nicht ins Schwarze.

Berücksichtigen Sie, dass beide Versionen auf allen meinen Testgeräten funktionieren.Ich bekomme nur die Ausnahme, wenn ich den Benutzerordner zu einer Nicht-Windows-Partition ändere.

Warum ist das? Und wo ist der Unterschied in den präsentierten Versionen?


bearbeiten

Okay, weil der erste und einzige Reaktion so weit, so scheint es mir, dass es immer noch nicht klar ist, was wirklich passiert: Wenn ich den obigen Code nehmen, setzen es in einer Windows Forms-Anwendung kompiliert und auf verschiedenen Computern ausgeführt wird (bei der Arbeit, zu Hause, egal), es funktioniert - sowohl Button1 als auch Button2 (mit den damit verknüpften Click-Funktionen) können so oft verwendet werden wie ich wie - keine Ausnahme geworfen. Wenn ich die Anwendung auf einem Computer ausführen, wo ich den Benutzerordner geändert, und klicken Sie auf Button1 das zweite Mal - Bam - IOException, Datei von Prozess gesperrt. Button2 funktioniert solange ich Taste1 nicht drücke.

Die erste Antwort impliziert, dass ich die Sperre für jedes System bekommen sollte. Aber ich NICHT (solange ich den Benutzerordner nicht ändere)! Ich habe es an jedem einzelnen Computer getestet, den ich in die Finger bekommen konnte - keine IOException. Ich habe ein neues System eingerichtet, nur um einige spezielle Änderungen an den Systemen in meinem Unternehmen auszuschließen - beide Funktionen von buttonx_Click haben funktioniert - auch keine Ausnahme. Ich habe sogar das Programm auf einem anderen Computer kompiliert - das gleiche Verhalten. Die einzigen drei Systeme, die diese Ausnahme ausgelöst haben, waren diejenigen mit dem geänderten Benutzerordner.

Bisher habe ich keine Ahnung, warum dieser Unterschied im Verhalten auftritt. Kann mir jemand helfen?

Jeder?

Antwort

6

Ja, das ist normal. Passiert auf jedem Betriebssystem, hat nichts mit dem Speicherort des Benutzerordners zu tun. Die PictureBox.Load() -Methode sollte verwendet werden, um Bilder von den Standorten anderen als das Dateisystem zu laden. Wie eine Website. Was langsam ist, verhindert das Einfrieren der Benutzeroberfläche, während der Download stattfindet.

Es verwendet intern einen FileStream, wenn festgestellt wird, dass die übergebene URL tatsächlich eine Datei und kein Website-Name ist. Dieser FileStream wird nicht entsorgt, bis die PictureBox selbst entsorgt wurde oder Sie die Load() -Methode erneut aufrufen. Eine Voraussetzung, da Image.FromStream() erfordert, dass der Stream lesbar bleibt, bis das Image nicht mehr verwendet wird. Es ist dieser FileStream, der eine Sperre für die Datei hält. Die Bereitstellung der PictureBox.Image ist nicht genug, um auch den FileStream zu entfernen, das Image-Objekt weiß nicht, dass es in einer Bildbox angezeigt wird.

Es gibt mehrere Möglichkeiten, dieses Problem zu lösen:

  • die Image-Eigenschaft Verwenden Sie statt Load(), weisen Sie von Image.FromFile(). Wenn Sie das Bild jetzt freigeben, wird auch die Sperre für die Datei aufgehoben. Wie Sie herausgefunden haben
  • Halten Sie ein Dummy-Bild herum, eines, das möglicherweise eine "Laden ..." Bitmap anzeigt. Load() zuerst, um die Sperre für die Datei zu lösen
  • Entsorgen Sie die PictureBox und neu erstellen.
+0

Während ich die Antwort nicht verstehen, es macht nur die Hälfte des beobachteten Verhaltens. Wenn es tatsächlich der Filestream ist, der das Bild sperrt, sollte das Verhalten nicht auf allen Systemen gleich sein?Warum kann ich das Sperrverhalten nur erreichen, wenn ich das System "lahmlege"? Wenn ich die FileStream-Version selber mache und nicht über den FileStream verfüge, bekomme ich die Ausnahme auf allen meinen Testsystemen (wie erwartet!). Also muss es einen Unterschied geben. – user3379589

+0

Ich bin überhaupt nicht davon überzeugt, dass dies für bestimmte Maschinen spezifisch ist. Sie haben gerade einen Fehlerbericht von einem Kunden erhalten, der ihn entdeckt hat und nach einer Erklärung gesucht hat, die erklären würde, warum nur dieser Kunde sie gesehen hat. Sie alle tun es, können es aber leicht vermeiden, weil es nicht üblich ist, das gleiche Bild zweimal zu laden. Repro es nur auf Ihrer eigenen Maschine. –

+0

Diese Anwendung (nicht das obige Konstrukt) verarbeitet nur eine einzelne Bitmap-Datei, die sie selbst erstellt und dem Benutzer anzeigt. Niemand kann seinen Namen ändern, es ist behoben. Der Benutzer hat also keinerlei Einfluss auf das Ergebnis. Der einfachste Weg, um beide Effekte mit weniger Code zu reproduzieren, war das obige Beispiel. Und dort können Sie verschiedene Dateinamen verwenden, solange das Dateiformat gleich ist. Das Ergebnis ist der gleiche Name "Test.fileformat". Aber darum geht es nicht. Wenn ich das obige Beispiel benutze, funktionieren beide Versionen auf jedem einzelnen System in meiner Firma, obwohl Version1 nicht sollte, wenn das, was du sagst, zutrifft. – user3379589