Wie löse ich das Problem mit Excel VBA?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Wenn eine Word Datei (oder eine andere Office Datei) geöffnet wird legt das System eine versteckte Datei an die so ähnlich heißt.

Bild zum Beitrag

Du kannst Prüfen, ob eine solche Datei vorhanden ist.
Es ist immer eine Tilde + $+ Underscore als Präfix vorm Dateinamen.
Öffne mal eine solche Datei mit dem TextEditor.
Du wirst sehen, dass dein User-Name auftaucht. Immer an der gleichen Stelle.
Ich habe in meinen Projekten auf Vorhandensein diese Datei geprüft, wenn ja, geöffnet und den UserNamen extrahiert und somit den aktuellen User warnen können,
damit es keine doppelten Zugriffe gibt.

 - (Computer, Microsoft Excel, VBA)
fx8350 
Fragesteller
 06.05.2022, 10:33

Ich habe es nun mit der Funktion verstanden und hätte vorher mal drauf kommen sollen, den Code mal schrittweise auszuführen:

Function IsFileOpen(FileName As String)
    Dim filenum As Integer, errnum As Integer
    On Error Resume Next
    filenum = FreeFile()
    Open FileName For Input Lock Read As #filenum
    Close filenum
    errnum = Err
    On Error GoTo 0
    Select Case errnum
    Case 0
    IsFileOpen = False
    Case 70
    IsFileOpen = True
    Case Else
    Error errnum
    End Select
End Function

Dann im Code:

Path = "\\..."
    file = Dir(Path & "XXX_*.docx")
    
    If IsFileOpen(Path & file) Then
    
    Else
    Zeile = ActiveCell.Row
    Set wordApp = CreateObject("Word.Application")
    d = Tabelle1.Cells(Zeile, 2)
    t = Tabelle1.Cells(Zeile, 3).Text

    Call Sleep(500)
 
    wordApp.Visible = True
    wordApp.Activate
    
    'On Error Resume Next
  
    Set doc = wordApp.Documents.Open(Path & file)

.....

    End If
    UserForm2.Show
End Sub

Die Userform anstatt einer Messagebox, da diese viel flexibler ist. Dort gibt es nun einen Button "Erneut versuchen" und Abbrechen. Erneut versuchen wiederholt die Sub, Abbrechen beendet.

Jetzt muss ich es nur noch schaffen, dass im Label der UserForm2 der Benutzer eingetragen wird, der das Dokument geöffnet hat.

0
fx8350 
Fragesteller
 06.05.2022, 10:38
@fx8350

Ok, funktioniert noch nicht ganz...

So ist richtig:

...
 If IsFileOpen(Path & file) Then
    UserForm2.Show
    
    Else
    Zeile = ActiveCell.Row
    Set wordApp = CreateObject("Word.Application")
    d = Tabelle1.Cells(Zeile, 2)
    t = Tabelle1.Cells(Zeile, 3).Text
...
0

Ggf ist während dem Testen eine Word Objekt vorhanden geblieben.
Ggf über den Task Manger (STRG+ALT+ENTF) dies prüfen und erst alle WORD Objekte beenden.
Auch dein Code muss am Ende das Objekt Set WordApp = nothing
vorhanden sein.

fx8350 
Fragesteller
 26.04.2022, 20:34

Also ich habe inzwischen festgestellt, dass es tatsächlich so war, dass noch ein Objekt offen war. Der Code funktioniert nun soweit. Ich hätte aber gerne eine Prüfung, ob die Vorlage bereits geöffnet ist und eine Msg-Box, die sich in diesem Fall öffnet, damit man diese erst schließt und ggf. speichert.

Dann soll die Msg-Box bestätigt werden und die Vorlage öffnet sich.

Ist so etwas möglich?

0
IchMalWiederXY  27.04.2022, 14:10
@fx8350

Dies ist auch möglich.
Hier musst du aber auf Windows zugreifen und durch eine Liste aller laufenden Prozesse iterieren um den richtigen zu beenden.
Beispiel Code gibt es im Web.
Recherchiere VBA Prozesse beenden. (ggf auch in englischer Sprache)
Wenn dies nicht zum Ziel führt kann ich auch meinen Code posten. (Den ich aber auch aus dem Web hatte)

1
fx8350 
Fragesteller
 27.04.2022, 14:37
@IchMalWiederXY

Wenn ich das richtig verstehe, würde dann der Prozess Word beendet? Oder tatsächlich nur das entsprechende Dokument?

Im ersten Fall wäre das nicht zielführend, da ggf. andere Word-Dokumente geöffnet sein könnten, auf die sich der Code nicht bezieht.

0
fx8350 
Fragesteller
 27.04.2022, 14:54
@fx8350

Ich sehe schon, es wird wieder kompliziert. Wollte prüfen ob das Dokument bereits geöffnet ist und eine Msg Box ausgeben, dass das Dokument erst (ggf.) gespeichert und dann geschlossen werden muss. und wenn das Dokument beendet wurde, soll der Code weiterlaufen.

0
fx8350 
Fragesteller
 27.04.2022, 16:03
@fx8350

Ich habe nun einiges gesichtet aber nichts davon verstehe ich.

Ich dachte dann, ich mache einen Code wenn ein Fehler ist:

On Error GoTo errorhandler
errorhandler:
MsgBox "Dokument ist bereits geöffnet!" & Chr(10) & "Bitte Dokument ggf. speicherung und schließen." & Chr(10) & "Abschließend mit OK fortsetzen.", vbOKCancel, vbExclamation
If vbOK Then
Set doc = WordApp.Documents.Open("Q:\\Test.docx")

...weiteren Code ausführen

Else
Exit Sub
...

Aber er öffnet ja nun schon das Dokument und prüft nicht erst. Und auch so funktioniert der Code nicht.

0
IchMalWiederXY  28.04.2022, 14:22
@fx8350

Im ErrorHandler 'nur' auf den Fehler hinweisen und was der Nutzer nun zu tun hat.
NICHT im ErrorHandler dann gemäß User Reaktion weiteren Code ausführen.
Den User mit seinen Korrekturen die Dinge von vorne beginnen lassen.
Denn im weiteren Code könnten wieder Fehler auftreten. ErrorHandler Kaskaden unbedingt vermeiden.

1
fx8350 
Fragesteller
 28.04.2022, 15:34
@IchMalWiederXY

Oh, danke für die Info. Ich hatte vorhin einen Code gefunden, der dem ersten Test nach vielversprechend aussah und mein Problem lösen konnte. Nur dummerweise habe ich nun das geänderte Dokument geschlossen und überschrieben und jetzt finde ich es wieder nicht. *nervt*

0
fx8350 
Fragesteller
 02.05.2022, 10:26
@fx8350

Nachtrag, ich habe den Code gefunden und angepasst, aber er funktioniert nicht:

Function IsFileOpen(filename As String)
    Dim filenum As Integer, errnum As Integer
    On Error Resume Next
    filenum = FreeFile()
    Open filename For Input Lock Read As #filenum
    Close filenum
    errnum = Err
    On Error GoTo 0
    Select Case errnum
    Case 0
    IsFileOpen = False
    Case 70
    IsFileOpen = True
    Case Else
    Error errnum
    End Select
End Function

Public Function LastUser(strPath As String) As String
    Dim strXl As String
    Dim strFlag1 As String, strflag2 As String
    Dim i As Integer, j As Integer
    Dim hdlFile As Long
    Dim lNameLen As Byte
   
    strFlag1 = Chr(0) & Chr(0)
    strflag2 = Chr(32) & Chr(32)
   
    hdlFile = FreeFile
    Open strPath For Binary As #hdlFile
        strXl = Space(LOF(hdlFile))
        Get 1, , strXl
    Close #hdlFile
   
    j = InStr(1, strXl, strflag2)
   
    #If Not VBA6 Then
        '// Xl97
        For i = j - 1 To 1 Step -1
            If Mid(strXl, i, 1) = Chr(0) Then Exit For
        Next
        i = i + 1
    #Else
        '// Xl2000+
        i = InStrRev(strXl, strFlag1, j) + Len(strFlag1)
    #End If
   
    '// IFM
    lNameLen = Asc(Mid(strXl, i - 3, 1))
    LastUser = Mid(strXl, i, lNameLen)
End Function

Zwar erkennt er in meiner Prozedur, dass das Dokument geöffnet ist (in dem Fall von mir). Jedoch hängt er sich in der Function "LastUser" hier auf:

Open strPath For Binary As #hdlFile

Ich erhalte Laufzeitfehler 52. Über Google finde ich raus, dass es sich ggf. um einen falschen Eintrag in der system.cfg handet. Da gehe ich aber nicht ran.

Jetzt bin ich noch immer keinen Schritt weiter :-(.

0
fx8350 
Fragesteller
 02.05.2022, 16:31
@IchMalWiederXY

Jetzt habe ich noch einen Code gefunden, der aber scheinbar nur prüft, ob Word geöffnet ist und nicht explizit das Dokument:

Sub test()
Dim wordApp As Word.Application
Dim doc As Word.Document
Dim FileName As String
Dim myObject As Object

FileName = "\\gsdg_*.docx"

On Error Resume Next

Set myObject = GetObject(, "Word.Application")
If Err.Number <> 0 Then
'If myObject Is Nothing Then
Set wordApp = CreateObject("Word.Application")

wordApp.Documents.Open FileName
wordApp.Visible = True
wordApp.Activate
wordApp.WindowState = 1
Else

For Each doc In wordApp
If StrComp(doc.FullName, FileName, vbTextCompare) = 0 Then

MsgBox "Dokument ist bereits geöffnet!"

End If

Next doc
End If

End Sub

Außerdem fehlt dann noch die Prüfung, welcher User das Dokument geöffnet hat (Rückmeldung über MsgBox). Also so einfach ist das Ganze (für mich) nicht...

0
IchMalWiederXY  02.05.2022, 16:40
@fx8350

Den User abfragen geht mit Application.GetUser (oder so ähnlich)
Also, es gibt die Liste der Offenen Applicationen.
Jede einzelne Applikation bietet dann ein Interface der zugehörigen offenen Dateien.
Hier ein Beispiel alle offenen Excel Datei zu checken. (Analog auch für Word, PowerPoint, etc)
Dim myWb as Workbook
For each myWB in Workbooks

next

1
fx8350 
Fragesteller
 03.05.2022, 15:01
@IchMalWiederXY

Bei mir funktioniert der Code oben nicht, er erkennt nur, dass Word geöffnet ist, bezieht sich aber nicht auf das Dokument. Ich verstehe es einfach nicht.

0
IchMalWiederXY  03.05.2022, 18:08
@fx8350
Die Word Applikation ist ein "erstes" Objekt. Das geöffnete Document ist ein zweites Object.Du hast eine Mischung aus "Early-" und "Late Binding" programmiert.Nur eines von beidem machen.Im Zweifel zu Beginn nur heraus finden dass Word Offen ist und den Nutzer anweisen dies zu schliessen und ggf Änderungen zu speichern.Dann dein Makro erneut laufen lassen und Word als einziger in den Fingern zu haben.Offenbar willst du den "letzten" User der das Dokument verändert hat ermitteln ?VBA User ermitteln der das Dokument geöffnet hat (herber.de)Der letzte user der etwas modifizerit hat ist ein Attribut in Word.   .BuiltInDocumentProperties("Author")


1
fx8350 
Fragesteller
 05.05.2022, 16:18
@IchMalWiederXY

Achso ist das. Also ich möchte prüfen, dass mein Word-Dokument, also die Vorlage, bereits geöffnet ist. Wenn das der Fall ist, soll eine Meldung erscheinen, dass das Dokument bereits geöffnet ist und wer das geöffnet hat.

Dann kann der andere Benutzer informiert werden, das Dokument bitte zu schließen und ggf. zu speichern.

Ohne diese Abfrage öffnet VBA ja auch ein Debuggen-Fenster und das möchte ich nicht haben. Ich denke, dass ich mit dieser Mitteilung diesen Fehler ordentlich auffange und den Benutzer zum Handeln bewege.

Vielleicht kann ich das auch so regeln:

Dokument-Vorlage geöffnet? Ja, Info mit Username

Msg-Box Weiter -> neue Prüfung oder Abbrechen. Dann muss eben wieder mit dem CommandButton gestartet werden, sobald man Rückmeldung hat.

Wie ich das nun verstehe, muss ich eine Prüfung einbauen, die jedes geöffnete Word-Dokument auf den Namen hin überprüft. Wenn dieser nicht gefunden wird, wird die Vorlage geöffnet und die Einträge aus Excel werden in Word übernommen.

Sowas habe ich schon versucht, aber irgendwie nicht richtig hinbekommen.

0