Mit Visual Studio an geöffnete Excel-Datei "ranhängen" und Makros starten

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von P1xelfehler.

    Mit Visual Studio an geöffnete Excel-Datei "ranhängen" und Makros starten

    Hallo,

    ich möchte ein einfaches Tool mit Visual Studio erstellen, mit dem ich ankreuzen kann, welche Makros in der Excel-Datei aufgeführt werden sollen - da ein einziges davon ja schon was länger dauert.

    Jetzt habe ich es hinbekommen, dass ich eine Excel-Datei starte (wenn ich den Pfad angebe) und von da aus Makros starten kann. Allerdings funktioniert es eben nicht mit einer bereits geöffneten Datei - so will ich es eigentlich haben - also unabhängig vom Pfad.

    Ideen?

    Hier mal das wichtigste vom Quellcode:

    VB.NET-Quellcode

    1. Dim oExcel As Excel.Application
    2. Dim oBook As Excel.Workbook
    3. Dim oBooks As Excel.Workbooks
    4. Dim Test
    5. Try 'Wenn schon an Excel dran
    6. Test = oBook.Name
    7. Catch ex As Exception 'Wenn nicht, dann Datei starten, dranhängen
    8. oExcel = New Excel.Application() '<-- Statt dem hier an die geöffnete Datei anhängen
    9. oExcel.Visible = True
    10. oBooks = oExcel.Workbooks
    11. oBook = oBooks.Open(TextBoxDateipfad.Text)
    12. End Try
    13. If ReparaturCheck.Checked = True Then oExcel.Run("Reparatur") 'Reparaturkosten berechnen, wenn es angekreuzt ist
    Probier's mal damit:

    VB.NET-Quellcode

    1. <DllImport("ole32.dll")> _
    2. Private Shared Function CreateItemMoniker(<MarshalAs(UnmanagedType.LPWStr)> ByVal lpszDelim As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszItem As String, ByRef ppmk As System.Runtime.InteropServices.ComTypes.IMoniker) As Integer
    3. End Function
    4. <DllImport("ole32.dll")> _
    5. Private Shared Function GetRunningObjectTable(ByVal reserved As UInteger, ByRef pprot As System.Runtime.InteropServices.ComTypes.IRunningObjectTable) As Integer
    6. End Function
    7. Private Function ExcelMacro_Startup() as Excel.Excel
    8. Dim xlApp As Excel.Excel = Nothing
    9. Dim xlAppObj As Object = Nothing
    10. 'holt eine Liste aller laufenden Prozesse die 'Excel' im Namen haben
    11. Dim proclist As Process() = Process.GetProcessesByName("Excel")
    12. Dim rot As System.Runtime.InteropServices.ComTypes.IRunningObjectTable
    13. Dim ppmk As System.Runtime.InteropServices.ComTypes.IMoniker
    14. Dim Meldung As String = "Es wurden mehrere Excel-Prozesse gefunden! Bitte die Kennung des gewünschten Prozesses angeben!" & vbCrLf
    15. Dim AktProc As Integer = 0
    16. 'durchläuft die Liste und hängt für jeden Prozess eine Zeile an den Meldungsstring
    17. For i = 0 To UBound(proclist)
    18. Meldung += CStr(i) & " " & proclist(i).MainWindowTitle & vbCrLf
    19. Next
    20. 'wenn mehrere Prozesse gefunden wurden wird jetzt gefragt, welcher ausgewählt werden - ist ziemlich quick'n dirty...
    21. If UBound(proclist) > 0 Then
    22. AktProc = InputBox(Meldung, "Excel-Sitzung auswählen!", 0)
    23. End If
    24. 'der ausgewählte Prozess wird übernommen (nur über die Position in der Auflistung - sehr quick'n dirty)
    25. Dim proc As Process = Process.GetProcessesByName("Excel")(AktProc)
    26. 'die nächsten 3 Zeilen hab ich auch nur kopiert - da ist es besser wenn Du mal die Hilfe bemühst...
    27. CreateItemMoniker(Nothing, "Excel_PID_" & proc.Id.ToString(), ppmk)
    28. GetRunningObjectTable(0, rot)
    29. rot.GetObject(ppmk, xlAppObj)
    30. 'jetzt wird der übernommene Prozess noch explizit in ein Excel-Object gecastet und zurückgegeben
    31. If xlAppObj IsNot Nothing Then
    32. xlApp = DirectCast(xlAppObj, excel.excel)
    33. End If
    34. Cursor.Current = Cursors.Default
    35. Return xlApp
    36. End Sub


    Ich hab das jetzt aus einer ähnlichen Anwendung von mir übernommen und ohne zu testen ein wenig angepasst. Bitte entschuldige evtl. Schreibfehler - ich hoffe der Sinn ist erkennbar und du kannst was draus machen...

    EDIT: habe oben noch zwei fehlende Deklarationen ergänzt und einige wenige Kommentare in den Code geschrieben. Habe jetzt keine Zeit weiter. Später gerne mehr...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thisoft“ ()

    Vielen Dank :)
    Das hilft mir schon weiter :)

    Das "Excel.Excel" findet er bei mir nicht. Hab ich einen Verweis/Import vergessen?

    Quellcode

    1. Dim xlApp As Excel.Excel = Nothing


    Das hier hab ich importert:

    Quellcode

    1. Imports Office = Microsoft.Office.Core
    2. Imports Microsoft.Office.Interop
    3. Imports VBIDE = Microsoft.Vbe.Interop
    4. Imports System.Runtime.InteropServices


    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „P1xelfehler“ ()

    Hallo, meine Arbeitsroutine zur Nachbearbeitung von generierten .csv-Dateien geht so:
    Verweis anlegen:
    (etwas ausführlicher:
    Verweis hinzufügen/ als .net-Komponente in den Projektmappeneingenschaften)



    Imports Microsoft.Office.Interop.Excel

    VB.NET-Quellcode

    1. Dim exclApp As Object
    2. Dim Datei As Object
    3. Try
    4. exclApp = GetObject("", "Excel.Application")
    5. With exclApp
    6. Datei = .Workbooks.OpenText(My.Application.Info.DirectoryPath & "\......csv", Local:=True)
    7. '.Columns("BA").NumberFormat = "000000000000" 'Beispiel für Nachbearbeitung
    8. End With
    9. Catch ex As Exception
    10. End Try


    d.h. ich arbeite mit einer geöffneten Datei, wahrscheinlich sollte auch das Makro laufen

    (Diese Interop-Sachen können ziemlich ärgerlich sein und sich gegenseitig auf den Füßen stehen. Es kann sein, dass es etwas bringt, in den Verweiseigenschaften die 'Interoptypen einbetten' auf 'False' zu setzen. Eine andere Fehlerquelle ist, dass eine höhere Officeversion deinstalliert wurde und noch Registry-Einträge hier Verwirrung stiften.)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „oliver3121“ ()

    Ja, Du musst noch den Verweis auf Excel in den Projekteigenschaften hinzufügen. Sorry - hab ich vergessen zu sagen...
    vb-paradise.de/index.php/Attachment/37114-ExcelVerweis-jpg/

    Dann den Import:

    VB.NET-Quellcode

    1. Imports xl = Microsoft.Office.Interop.Excel


    die geänderte Deklaration

    VB.NET-Quellcode

    1. Dim xlAppObj As xl.Application = Nothing


    und schließlich die geänderte Cast-Anweisung:

    VB.NET-Quellcode

    1. xlApp = DirectCast(xlAppObj, xl.Application)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thisoft“ ()

    oliver3121 schrieb:

    GetObject("", "Excel.Application")


    Anscheinend reicht das bereits aus! :)

    Er nimmt jetzt tatsächlich die bereits geöffnete Datei. Was ich noch brauche ist eine kurze Abfrage, ob schon eine Datei offen ist. Anscheinend ist nach dem Schließen von Excel oft trotzdem noch ein Prozess "EXCEL.EXE" offen. Also was tun?

    Ob ich diese Auswahlliste mit den offenen Excel-Prozessen von @Thisoft einbaue, weiß ich noch nicht. Cool gelöst ist es ja irgendwie^^
    Ja, so ist das mit dem "GetObject". Da bleibt meistens ein unsichtbarer Excel-Prozess im Hintergrund offen, trotz aller Versuche die geöffneten Automatisierungs-Objecte wieder ordentlich zu schließen, beenden, disposen, destroyen ;) etc. Aber um diesen Prozess dann noch abzuschießen (Kill) kannst Du auch meine Routine verwenden wenn Du sie ein klein wenig umbaust 8-)

    P1xelfehler schrieb:

    Anscheinend reicht das bereits aus
    Hatte ich das nicht bereits vor vier Tagen in Post #2 erwähnt? ;)

    OK, ein Leerparameter hat gefehlt, aber da hätte man doch mit wenig Mühe auch selbst drauf kommen können.
    Hättest du die Antwort etwas konstruktiver gestaltet, hätte ich wahrscheinlich sogar nachgeschaut, aber ein "geht nicht" ist nichts, was meinen Eifer ins Unermessliche treiben lässt.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --