Laden...

Excel: auf laufende Instanz zugreifen und schreiben

Erstellt von dansmo vor 13 Jahren Letzter Beitrag vor 13 Jahren 5.674 Views
D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren
Excel: auf laufende Instanz zugreifen und schreiben

Hallo,

ich möchte auf eine bestimmte Excel Datei und in dieser auf bestimmte Sheets zugreifen. Das klappt soweit gut, wenn die Datei geschlossen ist und vom Programm erst geöffnet wird. Dazu benutze ich folgenden Code:


/*Excel*/
            Excel.Sheets objSheets;
            Excel._Worksheet objSheet;
            try
            {
                // Open a specified workbook           
                objApp = new Excel.ApplicationClass();
                objBook = objApp.Workbooks.Open("I:/Test123.xls");
                objSheets = objBook.Worksheets;

                //write to the Signal sheet
                objSheet = (Excel._Worksheet)objSheets.get_Item("Test");

                /*Erstmal Sheet bereinigen*/
                objSheet.get_Range("C3:L18").set_Value(Missing.Value, "");

                objSheet.get_Range("B1").set_Value(Missing.Value, "Test123456");
}

Was muss ich anpassen, damit zunächst geprüft wird, ob diese Datei bereits geöffnet ist und dann direkt in diese geschrieben wird?
Ich habe zwar via Google einige Beispiele gefunden, diese aber nicht verstanden und hopffe mir kann jemand das konkret an meinem Code zeigen. Danke.

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

So, ich habe selbst noch einiges versucht. Im Moment hänge ich aber fest. Ich schaffe es, dass er die Datei öffnet, wenn sie nicht offen ist. An dem Punkt war ich ja schon heute Morgen.
Zusätzlich schaffe ich es jetzt, die Datei zu bearbeiten, wenn sie schon offen ist. Soweit so gut. Jetzt geht es darum beide zusammenzufügen, mit einer Prüfung, ob die Datei läuft. Falls nein: öffne sie, sonst beschreibe sie direkt.
Hier kommt aber ein Fehler. Ich denke, dass der Fehler direkt die Zeile eins in dem Ausschnitt betrifft. Evtl. klappt das mit der Überprüfung auf null nicht, wie kann ich das anders machen?
Der Fehler heißt ungefähr so:

Error: Ausnahme von HRESULT; 0x800A03EC bei Microsoft.Office.Interop.Excel

                if ((Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath + file) == null)
                {
                    //Open it since it is not yet open ----working fine
                    objApp = new Excel.ApplicationClass();
                    objWorkbook = objApp.Workbooks.Open(filePath + file);
                    objSheets = objWorkbook.Worksheets;
                }
                else
                {
                    //it is open, get it ------this part IS working fine
                    objWorkbook = (Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath + file);
                    objSheets = objWorkbook.Application.Worksheets;
                }

Auch die andere Alternative bringt leider keine Lösung. Zwar kommt dann der Fehler nicht, aber es wird in die geöffnete Datei nicht geschrieben.

                try
                {
                    //Open it since it is not yet open ----working fine
                    objApp = new Excel.ApplicationClass();
                    objWorkbook = objApp.Workbooks.Open(filePath + file);
                    objSheets = objWorkbook.Worksheets;
                }
                catch(Exception e)
                {
                    //it is open, get it ------this part IS working fine
                    objWorkbook = (Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath + file);
                    objSheets = objWorkbook.Application.Worksheets;
                }

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Habs gelöst:

                if(!isFileOpenOrReadOnly(filePath + file))
                {
                    //Open it since it is not yet open ----working fine
                    objApp = new Excel.ApplicationClass();
                    objWorkbook = objApp.Workbooks.Open(filePath + file);
                    objSheets = objWorkbook.Worksheets;
                }
                else
                {
                    //it is open, get it ------this part IS working fine
                    objWorkbook = (Excel.Workbook)System.Runtime.InteropServices.Marshal.BindToMoniker(filePath + file);
                    objSheets = objWorkbook.Application.Worksheets;
                }

und de funktion ist

        public bool isFileOpenOrReadOnly(string file)
        {
            try
            {
                //first make sure it's not a read only file
                if ((File.GetAttributes(file) & FileAttributes.ReadOnly) != FileAttributes.ReadOnly)
                {
                    //first we open the file with a FileStream
                    using (FileStream stream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None))
                    {
                        try
                        {
                            stream.ReadByte();
                            return false;
                        }
                        catch (IOException)
                        {
                            return true;
                        }
                        finally
                        {
                            stream.Close();
                            stream.Dispose();
                        }
                    }
                }
                else
                    return true;
            }
            catch (IOException)
            {
                return true;
            }
        }  
1.044 Beiträge seit 2008
vor 13 Jahren

Hallo dansmo,

du hast zwar das Problem gelöst, uns aber leider nicht mitgeteilt, was der Grund für das Verhalten ist. Andere, die das gleiche Problem haben und die Forensuche verwenden, werden dann leider nicht wissen, warum die Fehlermeldung kommt. Es wäre nett, wenn du das beschrieben könntest.

Ich nehme dir die Arbeit mal ab: Der Grund ist, dass Excel die Datei offen hat. Weil Excel die Datei offen hat, ist somit der Stream offen. Erst wenn der Stream wieder geschlossen ist, kann man die Datei wieder lesen. Wenn nun Excel die Datei verwendet und eine andere Anwendung versucht, die Datei zu lesen, kommt es zu dieser Fehlermeldung. Aus diesem Grund muss man vorher prüfen, ob es möglich ist, die Datei zu lesen.

zero_x

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Ja, hast du recht. Danke.

Jetzt habe ich noch ein kleineres Problem, das ich der Vollständigkeit halber auch gerne noch lösen möchte:

Wenn mehrere Excel Instanzen geöffnet sind dann kommt es zu Problemen. Wie kann ich das noch einfügen, damit der Code immer (naja, fast immer) richtig funktioniert?

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Jetzt habe ich noch eine Anschlussfrage:

Auf meinem "Entwickler PC" habe ich Office 2010 installiert, auf dem "Arbeits PC" jedoch Office 2003. Dort funktioniert es jetzt leider nicht, wenn ich meine Anwendung am Arbeits PC laufen lass.
Was muss ich tun damit das trotzdem geht, egal welche Office Version der user benutzt?

1.820 Beiträge seit 2005
vor 13 Jahren

Hallo!

Um versionsunabhängig auf Office-Instanzen zuzugreifen, bleibt dir entweder, alle dafür benötigten Office-Wrapper einzubinden, oder komplett auf COM-LateBinding umzusteigen, zu zweiterem gobt's sogar schon fertige Komponenten hier im Forum.

Nobody is perfect. I'm sad, i'm not nobody 🙁

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Hallo Tom,

ich habe zu dem Late Binding code gefunden, ja. Leider habe ich keine Ahnung, wie ich meinen obigen Code verändern muss, damit das klappt. Ich war ja schon froh, dass es überhaupt funktioniert hat. Kann mir denn jemand helfen dass in meinen Code zu integrieren?

Gelöschter Account
vor 13 Jahren

Zeig doch mal den Code.
Bzw. wo hast du welchen Code gefunden?

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Es geht um den Code in diesem Thrad http://www.mycsharp.de/wbb2/thread.php?threadid=77102und dessen Integration mit meinem obigen Code. Ich gehe davon aus, dass das der richtige Weg ist verstehe aber vom Code ehrlich gesagt nichts.

Gelöschter Account
vor 13 Jahren

Was verstehst du am Code nicht.
Rainbird erklärt das soweit ganz gut finde ich.

Alternativ möchte ich dir ein kleines Projekt von mir empfehlen
das dir dass bietet was du brauchst.

http://excel.codeplex.com

D
dansmo Themenstarter:in
14 Beiträge seit 2011
vor 13 Jahren

Hallo Sebastian,

danke für dein Projekt, jetzt geht es.
Eine kleine Frage dazu:
vorher konnte ich ein einzelnes Worksheet so ansteuern:

objSheet = (Excel._Worksheet)objSheets.get_Item("Signal");

Mit deiner dll geht das jetzt nicht mehr, anscheinend kann ich das nur noch nach Nummerierung aufrufen?

objSheet = (Excel._Worksheet)objSheets[1];

Oder geht das so auch?

objSheet = (Excel._Worksheet)objSheets["Signal"];

Danke für Feedback,
dansmo

Gelöschter Account
vor 13 Jahren

Hallo dansmo,

Klar das geht auch so


Excel.Worksheet workSheet =  workBook.Worksheets["Signal"]; 

Wenn du Fragen zu LateBindingApi.Excel hast dann stelle die bitte in dem
myCSharp Thread dazu:
LateBindingApi.Excel - Framework für den versionsfreien Zugriff

Viel Erfolg!
Sebastian