是否可以使用VBA代码读取Windows事件查看器?

是否可以使用VBA代码读取Windows事件查看器?,vba,event-viewer,Vba,Event Viewer,我希望能够从VBA代码中读取Windows事件查看器项目(例如,当用户登录或注销其工作站时)十多年前,我从某个地方下载了一个代码示例。不幸的是,我不能提供作者的名字或来源,以给予信贷的地方,信贷到期。下面是封装事件日志读取的模块。这是一个示例项目的一部分,我上传了该项目,以便您了解如何使用该模块。这可能不是你想要的,但它应该给你一个良好的开端 Option Explicit Private Const EVENTLOG_SEQUENTIAL_READ = &H1 Private Co

我希望能够从VBA代码中读取Windows事件查看器项目(例如,当用户登录或注销其工作站时)

十多年前,我从某个地方下载了一个代码示例。不幸的是,我不能提供作者的名字或来源,以给予信贷的地方,信贷到期。下面是封装事件日志读取的模块。这是一个示例项目的一部分,我上传了该项目,以便您了解如何使用该模块。这可能不是你想要的,但它应该给你一个良好的开端

Option Explicit


Private Const EVENTLOG_SEQUENTIAL_READ = &H1
Private Const EVENTLOG_SEEK_READ = &H2
Private Const EVENTLOG_FORWARDS_READ = &H4
Private Const EVENTLOG_BACKWARDS_READ = &H8

Private Type EVENTLOGRECORD
     Length As Long               'Length of full record
     Reserved As Long             'Used by the service
     RecordNumber As Long         'Absolute record number
     TimeGenerated As Long        'Seconds since 1-1-1970
     TimeWritten As Long          'Seconds since 1-1-1970
     EventID As Long
     EventType As Integer
     NumStrings As Integer
     EventCategory As Integer
     ReservedFlags As Integer     'For use with paired events (auditing)
     ClosingRecordNumber As Long  'For use with paired events (auditing)
     StringOffset As Long         'Offset from beginning of record
     UserSidLength As Long
     UserSidOffset As Long
     DataLength As Long
     DataOffset As Long           'Offset from beginning of record
End Type

Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (dst As Any, src As Any, ByVal Size As Long)
Private Declare Function OpenEventLog Lib "advapi32" Alias "OpenEventLogA" (ByVal lpUNCServerName As String, ByVal lpEventSourceName As String) As Long
Private Declare Function CloseEventLog Lib "advapi32.dll" (ByVal hEventLog As Long) As Long
Private Declare Function GetNumberOfEventLogRecords Lib "advapi32.dll" (ByVal hEventLog As Long, NumberOfRecords As Long) As Long
Private Declare Function ReadEventLog Lib "advapi32.dll" Alias "ReadEventLogA" (ByVal hEventLog As Long, ByVal dwReadFlags As Long, ByVal dwRecordOffset As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, pnBytesRead As Long, pnMinNumberOfBytesNeeded As Long) As Long

Public Function ReadEvents(ByVal ServerName As String, ByVal EventType As String) As String
    'Returns the eventlog content as a vbcrlf separated string
    Dim ret As Long, EventLogHwd As Long, EvtRecNo As Long, rBytesRead As Long, rBytesNeeded As Long
    Dim rBuff As EVENTLOGRECORD, EvtReadFlags As Long
    Dim eBuff() As Byte, StrucLen As Long, EvtRecLen As Long
    Dim strBuffer As String, strStart As Long, strStop As Long, strCount As Long, eBytePointer As Long
    Dim eSourceName As String, eComputerName As String, ThisString As String

    Dim tmpString As String

    StrucLen = Len(rBuff)
    ReDim eBuff(16384)
    EvtReadFlags = EVENTLOG_SEQUENTIAL_READ Or EVENTLOG_FORWARDS_READ

    EventLogHwd = OpenEventLog(ServerName, EventType)
    If EventLogHwd = 0 Then Exit Function

    ret = GetNumberOfEventLogRecords(EventLogHwd, EvtRecNo)
    If ret = 0 Then Exit Function

    Do While rBuff.RecordNumber < EvtRecNo
        'Reads all events in 16K chunks
        ret = ReadEventLog(EventLogHwd, EvtReadFlags, rBuff.RecordNumber + 1, eBuff(0), 16384, rBytesRead, rBytesNeeded)
        If ret = 0 Then Exit Function

        eBytePointer = 0
        Do While eBytePointer < rBytesRead
            CopyMem rBuff, eBuff(eBytePointer), StrucLen
            EvtRecLen = rBuff.Length
            'Here rBuff is already filled, then we can filter events

            strBuffer = Space(EvtRecLen - StrucLen)
            CopyMem ByVal strBuffer, eBuff(StrucLen + eBytePointer), (EvtRecLen - StrucLen)
            eBytePointer = eBytePointer + EvtRecLen

            strStart = 1
            strStop = InStr(strStart, strBuffer, Chr(0))
            eSourceName = Mid(strBuffer, strStart, strStop - strStart)

            strStart = strStop + 1
            strStop = InStr(strStart, strBuffer, Chr(0))
            eComputerName = Mid(strBuffer, strStart, strStop - strStart)

            'Put all strings together, we can parse later...
            If rBuff.NumStrings > 0 Then
                strStart = rBuff.StringOffset - StrucLen + 1
                ThisString = ""
                For strCount = 1 To rBuff.NumStrings
                    strStop = InStr(strStart, strBuffer, Chr(0))
                    ThisString = ThisString & Mid(strBuffer, strStart, strStop - strStart) & " "
                    strStart = strStop + 1
                Next strCount
                'Here 'ThisString' contains all strings of the current event
                If Len(tmpString) > 0 Then
                    tmpString = tmpString & vbCrLf
                End If
                tmpString = tmpString & "(Source: " & eSourceName & ") " & ThisString


            End If
        Loop
    Loop

    ret = CloseEventLog(EventLogHwd)

    ReadEvents = tmpString

End Function
选项显式
Private Const EVENTLOG\u SEQUENTIAL\u READ=&H1
Private Const EVENTLOG\u SEEK\u READ=&H2
Private Const EVENTLOG\u FORWARDS\u READ=&H4
Private Const EVENTLOG\u BACKWARDS\u READ=&H8
私有类型事件日志记录
长度等于完整记录的长度
保留为服务使用的“长”
记录编号为“长”绝对记录编号
自1970年1月1日以来生成的时间为“秒”
自1970年1月1日起写入的时间为“秒”
EventID尽可能长
EventType为整数
作为整数的numstring
EventCategory为整数
ReservedFlags As Integer'用于成对事件(审核)
ClosingRecordNumber As Long'用于成对事件(审核)
StringOffset作为“从记录开始的长偏移量”
UserSidLength尽可能长
UserSidOffset尽可能长
数据长度等于
数据偏移量作为“从记录开始的长偏移量”
端型
私有声明子copymemlib“kernel32”别名“rtlmovemory”(dst为任意,src为任意,ByVal大小为任意长)
私有声明函数OpenEventLog Lib“advapi32”别名“OpenEventLogA”(ByVal lpUNCServerName作为字符串,ByVal lpEventSourceName作为字符串),长度为
私有声明函数CloseEventLog Lib“advapi32.dll”(ByVal hEventLog作为Long)作为Long
私有声明函数GetNumberOfEventLogRecords Lib“advapi32.dll”(ByVal hEventLog为Long,NumberOfRecords为Long)为Long
私有声明函数ReadEventLog Lib“advapi32.dll”别名“ReadEventLogA”(ByVal hEventLog为长,ByVal dwReadFlags为长,ByVal dwRecordOffset为长,lpBuffer为长,ByVal nNumberOfBytesToRead为长,pnBytesRead为长,PnMinNumberOfBytes为长)为长
公共函数ReadEvents(ByVal ServerName作为字符串,ByVal EventType作为字符串)作为字符串
'以vbcrlf分隔字符串的形式返回事件日志内容
Dim ret为Long,EventLogHwd为Long,EvtRecNo为Long,rBytesRead为Long,RBytesNeed为Long
将rBuff变暗为事件日志记录,将EVTRADE标记变长
Dim eBuff()为字节,StrucLen为长,EvtRecLen为长
Dim strBuffer为字符串、strStart为长、strStop为长、strCount为长、eBytePointer为长
Dim eSourceName作为字符串,eComputerName作为字符串,ThisString作为字符串
将tmpString设置为字符串
StrucLen=Len(rBuff)
ReDim eBuff(16384)
EVTRADEFLAGS=EVENTLOG\u SEQUENTIAL\u READ或EVENTLOG\u FORWARDS\u READ
EventLogHwd=OpenEventLog(服务器名,事件类型)
如果EventLogHwd=0,则退出函数
ret=GetNumberOfEventLogRecords(EventLogHwd,EvtRecNo)
如果ret=0,则退出函数
当rBuff.RecordNumber0,则
strStart=rBuff.StringOffset-StrucLen+1
ThisString=“”
对于strCount=1到rBuff.NumStrings
strStop=InStr(strStart,strBuffer,Chr(0))
ThisString=ThisString&Mid(strBuffer、strStart、strStop-strStart)和“”
strStart=strStop+1
下一个strCount
'此处'ThisString'包含当前事件的所有字符串
如果Len(tmpString)>0,则
tmpString=tmpString&vbCrLf
如果结束
tmpString=tmpString&“(源:&eSourceName&”)和此字符串
如果结束
环
环
ret=CloseEventLog(EventLogHwd)
ReadEvents=tmpString
端函数

十多年前,我从某处下载了一个代码示例。不幸的是,我不能提供作者的名字或来源,以给予信贷的地方,信贷到期。下面是封装事件日志读取的模块。这是一个示例项目的一部分,我上传了该项目,以便您了解如何使用该模块。这可能不是你想要的,但它应该给你一个良好的开端

Option Explicit


Private Const EVENTLOG_SEQUENTIAL_READ = &H1
Private Const EVENTLOG_SEEK_READ = &H2
Private Const EVENTLOG_FORWARDS_READ = &H4
Private Const EVENTLOG_BACKWARDS_READ = &H8

Private Type EVENTLOGRECORD
     Length As Long               'Length of full record
     Reserved As Long             'Used by the service
     RecordNumber As Long         'Absolute record number
     TimeGenerated As Long        'Seconds since 1-1-1970
     TimeWritten As Long          'Seconds since 1-1-1970
     EventID As Long
     EventType As Integer
     NumStrings As Integer
     EventCategory As Integer
     ReservedFlags As Integer     'For use with paired events (auditing)
     ClosingRecordNumber As Long  'For use with paired events (auditing)
     StringOffset As Long         'Offset from beginning of record
     UserSidLength As Long
     UserSidOffset As Long
     DataLength As Long
     DataOffset As Long           'Offset from beginning of record
End Type

Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (dst As Any, src As Any, ByVal Size As Long)
Private Declare Function OpenEventLog Lib "advapi32" Alias "OpenEventLogA" (ByVal lpUNCServerName As String, ByVal lpEventSourceName As String) As Long
Private Declare Function CloseEventLog Lib "advapi32.dll" (ByVal hEventLog As Long) As Long
Private Declare Function GetNumberOfEventLogRecords Lib "advapi32.dll" (ByVal hEventLog As Long, NumberOfRecords As Long) As Long
Private Declare Function ReadEventLog Lib "advapi32.dll" Alias "ReadEventLogA" (ByVal hEventLog As Long, ByVal dwReadFlags As Long, ByVal dwRecordOffset As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, pnBytesRead As Long, pnMinNumberOfBytesNeeded As Long) As Long

Public Function ReadEvents(ByVal ServerName As String, ByVal EventType As String) As String
    'Returns the eventlog content as a vbcrlf separated string
    Dim ret As Long, EventLogHwd As Long, EvtRecNo As Long, rBytesRead As Long, rBytesNeeded As Long
    Dim rBuff As EVENTLOGRECORD, EvtReadFlags As Long
    Dim eBuff() As Byte, StrucLen As Long, EvtRecLen As Long
    Dim strBuffer As String, strStart As Long, strStop As Long, strCount As Long, eBytePointer As Long
    Dim eSourceName As String, eComputerName As String, ThisString As String

    Dim tmpString As String

    StrucLen = Len(rBuff)
    ReDim eBuff(16384)
    EvtReadFlags = EVENTLOG_SEQUENTIAL_READ Or EVENTLOG_FORWARDS_READ

    EventLogHwd = OpenEventLog(ServerName, EventType)
    If EventLogHwd = 0 Then Exit Function

    ret = GetNumberOfEventLogRecords(EventLogHwd, EvtRecNo)
    If ret = 0 Then Exit Function

    Do While rBuff.RecordNumber < EvtRecNo
        'Reads all events in 16K chunks
        ret = ReadEventLog(EventLogHwd, EvtReadFlags, rBuff.RecordNumber + 1, eBuff(0), 16384, rBytesRead, rBytesNeeded)
        If ret = 0 Then Exit Function

        eBytePointer = 0
        Do While eBytePointer < rBytesRead
            CopyMem rBuff, eBuff(eBytePointer), StrucLen
            EvtRecLen = rBuff.Length
            'Here rBuff is already filled, then we can filter events

            strBuffer = Space(EvtRecLen - StrucLen)
            CopyMem ByVal strBuffer, eBuff(StrucLen + eBytePointer), (EvtRecLen - StrucLen)
            eBytePointer = eBytePointer + EvtRecLen

            strStart = 1
            strStop = InStr(strStart, strBuffer, Chr(0))
            eSourceName = Mid(strBuffer, strStart, strStop - strStart)

            strStart = strStop + 1
            strStop = InStr(strStart, strBuffer, Chr(0))
            eComputerName = Mid(strBuffer, strStart, strStop - strStart)

            'Put all strings together, we can parse later...
            If rBuff.NumStrings > 0 Then
                strStart = rBuff.StringOffset - StrucLen + 1
                ThisString = ""
                For strCount = 1 To rBuff.NumStrings
                    strStop = InStr(strStart, strBuffer, Chr(0))
                    ThisString = ThisString & Mid(strBuffer, strStart, strStop - strStart) & " "
                    strStart = strStop + 1
                Next strCount
                'Here 'ThisString' contains all strings of the current event
                If Len(tmpString) > 0 Then
                    tmpString = tmpString & vbCrLf
                End If
                tmpString = tmpString & "(Source: " & eSourceName & ") " & ThisString


            End If
        Loop
    Loop

    ret = CloseEventLog(EventLogHwd)

    ReadEvents = tmpString

End Function
选项显式
Private Const EVENTLOG\u SEQUENTIAL\u READ=&H1
Private Const EVENTLOG\u SEEK\u READ=&H2
Private Const EVENTLOG\u FORWARDS\u READ=&H4
Private Const EVENTLOG\u BACKWARDS\u READ=&H8
私有类型事件日志记录
长度等于完整记录的长度
保留为服务使用的“长”
记录编号为“长”绝对记录编号
自1970年1月1日以来生成的时间为“秒”
时间写得一样长