Tutorial Registrare modifiche in un file di LOG

Stato
Chiusa ad ulteriori risposte.

giulianovac

Access/VBA Expert
Expert
9 Giugno 2018
1.709
83
Italy
2013 2019
126
Ciao a tutti!

PREMESSA
Spesso, in un azienda, c'è l'esigenza di rispondere a questa domanda:
Chi ha modificato cosa?
Ma quando un file è accessibile a molti utenti, è impossibile trovare una risposta.

A meno che non ci prendiamo la briga di implementare la gestione di un file di LOG!

Questo esempio dimostra come sia davvero semplice prendere nota delle modifiche apportate a qualsiasi cella in tutti i fogli del file e registrarle in un file di LOG, che non è altro che un semplice file di testo, strutturato... come ci pare.

Nel caso specifico, utilizzo le seguenti informazioni:
Visual Basic:
- DATE TIME  data ed ora di modifica
- USER       utente che ha eseguito la modifica
- SHEET      il foglio in cui è stata eseguita
- CELL       indirizzo della cella modificata
- OLD        il valore contenuto PRIMA della modifica
- NEW        il valore contenuto DOPO la modifica
Esempio:
Visual Basic:
DATE TIME              USER      SHEET      CELL    OLD       NEW
2019-03-26 19:55:21    andrea    Foglio2    $B$1    [NULL]    2
2019-03-26 19:55:23    andrea    Foglio2    $C$1    [NULL]    3
2019-03-26 19:55:25    andrea    Foglio2    $D$1    [NULL]    4
2019-03-26 19:55:51    pippo     Foglio2    $A$1    1         A
2019-03-26 19:59:31    pluto     Foglio1    $C$2    [NULL]    ABC
Il concetto è molto semplice, vi sono due fasi:
  1. Nell'evento Workbook_SheetSelectionChange(), ovvero quando l'utente seleziona una cella, registro il valore corrente nella variabile m_Old.
    Se non contiene alcun valore m_Old sarà uguale a "[NULL]".
    In caso di modifica, m_Old conterrà il valore della cella prima della modifica

  2. Nell'evento Workbook_SheetChange() la modifica alla cella corrente verrà registrata nel file di LOG
Ecco il codice completo che trovate nel workbook:

Visual Basic:
Option Explicit
Dim m_Old As String
Dim sep As String
Dim MaxCellLimit As Long

Function GetSeparator() As String
    GetSeparator = "|"
End Function
Function GetLimit() As Long
    GetLimit = 100
End Function

Function GetArea(ByRef Target As Range) As String
    Rem Se l'utente seleziona un range di celle restituisce tutti i valori ed indica l'indirizzo dell'area selezionata
    Dim sOld As String
    Dim i As Long
    Dim j As Long
  
    sep = GetSeparator()
    MaxCellLimit = GetLimit()

    If Target.Cells.Count > MaxCellLimit Then
        GetArea = "Area=" & CStr(Target.Cells.Count)
    Else
        For i = 1 To Target.Cells.Rows.Count
            For j = 1 To Target.Cells.Columns.Count
                If Target.Cells.Cells(i, j) = vbNullString Then
                    sOld = sOld & sep & "[NULL]"
                Else
                    sOld = sOld & sep & Target.Cells.CurrentRegion.Cells(i, j)
                End If
            Next j
        Next
        GetArea = sOld & sep & " (Area=" & Target.Cells.CurrentRegion.Address & ")"
    End If
End Function


Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    Dim nrFile As Integer
    Dim sLine As String
    Dim sFilePath As String
    Dim sHeader As String
  
    sFilePath = ThisWorkbook.Path & "\LOG.txt"
    sHeader = "DATE TIME" & vbTab & vbTab & "USER" & vbTab & "SHEET" & vbTab & "CELL" & vbTab & "OLD" & vbTab & "NEW"
  
    nrFile = freefile()
  
    Rem ------------------------------------------------------------
    Rem Compongo la riga con i valori dei campi richiesti
    Rem ------------------------------------------------------------
    sLine = Format$(Date, "YYYY-MM-DD") & " " & Time
    sLine = sLine & vbTab & Environ("USERNAME")
    sLine = sLine & vbTab & Sh.Name
    sLine = sLine & vbTab & Target.Address
    sLine = sLine & vbTab & IIf(IsEmpty(m_Old), "[NULL]", m_Old)
  
    If Target.Cells.Count > 1 Then
        sLine = sLine & vbTab & GetArea(Target)
    Else
        sLine = sLine & vbTab & IIf(Target.Value = "", "[NULL]", Target.Value)
    End If
  
    Rem ------------------------------------------------------------
    Rem Registro le informazioni e chiudo il file di LOG
    Open sFilePath For Append As #nrFile
    If FileLen(sFilePath) = 0 Then
        Rem Aggiunge l'header se è un nuovo file
        Print #nrFile, sHeader
    End If
    Print #nrFile, sLine
    Close #nrFile
    Rem ------------------------------------------------------------
  
End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    If Target.Cells.Count > 1 Then
        m_Old = GetArea(Target)
    Else
        m_Old = Target.Value
    End If
    Debug.Print m_Old
End Sub
Nell'esempio allegato, per praticità, il file di LOG viene registrato nella stessa cartella in cui si trova il file:
sFilePath = ThisWorkbook.Path & "\LOG.txt"

Ma nella realtà, in un'azienda, sarà opportuno indicare una cartella condivisa della rete aziendale utilizzando la sintassi seguente:
sFilePath = "\\NOMESERVER\PERCORSOCONDIVISO\LOG.txt"
Ad esempio (nomi a caso):
sFilePath = "\\SrvApp01\Commerciale\Registri\pippo\pluto\paperino\LOG.txt"


In un contesto aziendale sarebbe utile progettere il codice VBA da manomissioni 'esterne' impostando una password nelle Proprietà del progetto VBA.

IMPORTANTE
Se il file LOG.txt non esiste viene creato automaticamente ed altrettanto automaticamente vengono inserite le intestazioni di colonna.
La sola cosa che dobbiamo preoccuparci è che in quella cartella si abbiano i permessi di scrittura.


Il progetto ed ulteriori dettagli importanti li trovate nella sezione Lavori e giochi con Excel e altri applicativi :
 
Ultima modifica:
Stato
Chiusa ad ulteriori risposte.

Sostieni ForumExcel

Aiutaci a sostenere le spese e a mantenere online la community attraverso una libera donazione!