JNA事件日志阅读器

时间:2012-03-30 20:10:18

标签: events logging jna

我使用以下代码使用JNA读取Windows应用程序事件日志。我希望能够指定从哪个事件开始而不是始终从第一个事件开始。有没有人有任何建议?

import java.io.IOException;
import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinNT.*;
import com.sun.jna.ptr.IntByReference;

public class test {

    public static void main(String[] args) throws NumberFormatException, IOException {

        HANDLE h = Advapi32.INSTANCE.OpenEventLog("ServerName", "Application");
        IntByReference pnBytesRead = new IntByReference();
        IntByReference pnMinNumberOfBytesNeeded = new IntByReference();
        Memory buffer = new Memory(1024 * 64);
        IntByReference pOldestRecord = new IntByReference();
        assertTrue(Advapi32.INSTANCE.GetOldestEventLogRecord(h, pOldestRecord));

        int dwRecord = pOldestRecord.getValue();
        int rc = 0;
        while(true) {
            if (! Advapi32.INSTANCE.ReadEventLog(h, WinNT.EVENTLOG_SEQUENTIAL_READ | WinNT.EVENTLOG_FORWARDS_READ, 
                        0, buffer, (int) buffer.size(), pnBytesRead, pnMinNumberOfBytesNeeded)) {
                rc = Kernel32.INSTANCE.GetLastError();
                if (rc == W32Errors.ERROR_INSUFFICIENT_BUFFER) {
                    buffer = new Memory(pnMinNumberOfBytesNeeded.getValue());
                    continue;
                }                
                break;
            }
            int dwRead = pnBytesRead.getValue();
            Pointer pevlr = buffer;
            while (dwRead > 0) 
            {
                EVENTLOGRECORD record = new EVENTLOGRECORD(pevlr);
                System.out.println(dwRecord + " Event ID: " + record.EventID.intValue());

                dwRecord++;
                dwRead -= record.Length.intValue();
                pevlr = pevlr.share(record.Length.intValue());
            }
       }
       assertTrue(rc == W32Errors.ERROR_HANDLE_EOF);
       assertTrue(Advapi32.INSTANCE.CloseEventLog(h));        
   }


   private static void assertTrue(boolean getOldestEventLogRecord) {
   }

}

1 个答案:

答案 0 :(得分:3)

邦多,这是一个可能的解决方案。在我的测试中,它读取Application事件下的所有570个事件日志;每个事件日志都会详细显示其事件日志记录数据。

代码解决方案:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Arrays;

import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinNT.*;
import com.sun.jna.ptr.IntByReference;

public class Test {

    public static void main(String[] args) throws NumberFormatException, IOException {

        HANDLE h = com.sun.jna.platform.win32.Advapi32.INSTANCE.OpenEventLog(null, "Application");
        IntByReference pnBytesRead = new IntByReference();
        IntByReference pnMinNumberOfBytesNeeded = new IntByReference();

        IntByReference pOldestRecord = new IntByReference();
        assertTrue(com.sun.jna.platform.win32.Advapi32.INSTANCE.GetOldestEventLogRecord(h, pOldestRecord));
        int dwRecord = pOldestRecord.getValue();
        System.out.println("OLD: " + dwRecord);
        IntByReference pRecordCount = new IntByReference();
        assertTrue(com.sun.jna.platform.win32.Advapi32.INSTANCE.GetNumberOfEventLogRecords(h, pRecordCount));
        int dwRecordCnt = pRecordCount.getValue();
        System.out.println("CNT: " + dwRecordCnt);

        int bufSize = 0x7ffff; //(r.size()) * 2048;
        Memory buffer = new Memory(bufSize);
        int rc = 0;
        int cnt = 0;
        while(com.sun.jna.platform.win32.Advapi32.INSTANCE.ReadEventLog(h, 
                WinNT.EVENTLOG_SEEK_READ  /*
                | WinNT.EVENTLOG_SEQUENTIAL_READ */ 
                | WinNT.EVENTLOG_FORWARDS_READ /*
                | WinNT.EVENTLOG_BACKWARDS_READ*/
                , 
                dwRecord, buffer, 
                bufSize, 
                pnBytesRead, 
                pnMinNumberOfBytesNeeded)) {

            rc = Kernel32.INSTANCE.GetLastError();
            if (rc == W32Errors.ERROR_INSUFFICIENT_BUFFER) {
                break;
            }        

            int dwRead = pnBytesRead.getValue();
            Pointer pevlr = buffer;

            while (dwRead > 0) 
            {
                cnt++;
                EVENTLOGRECORD record = new EVENTLOGRECORD(pevlr);
                System.out.println("------------------------------------------------------------");
                System.out.println(cnt+". " + dwRecord + " Event ID: " + record.EventID.shortValue() + " SID: " + record.UserSidLength);

                dwRecord++;

                // WCHAR SourceName[]
                // WCHAR Computername[]
                {
                    ByteBuffer names = pevlr.getByteBuffer(record.size(), 
                            (record.UserSidLength.intValue() != 0 ? record.UserSidOffset.intValue() : record.StringOffset.intValue()) - record.size());
                    names.position(0);
                    CharBuffer namesBuf = names.asCharBuffer();
                    String[] splits = namesBuf.toString().split("\0");
                    System.out.println("SOURCE NAME: \n" + splits[0]);
                    System.out.println("COMPUTER NAME: \n" + splits[1]);
                }
                // SID   UserSid
                if (record.UserSidLength.intValue() != 0){
                    ByteBuffer sid = pevlr.getByteBuffer(record.UserSidOffset.intValue(), record.UserSidLength.intValue());
                    sid.position(0);
                    //CharBuffer sidBuf = sid.asCharBuffer();
                    byte[] dst = new byte[record.UserSidLength.intValue()];
                    sid.get(dst);
                    System.out.println("SID: \n" + Arrays.toString(dst));
                }
                else {
                    System.out.println("SID: \nN/A");
                }
                // WCHAR Strings[]
                {
                    ByteBuffer strings = pevlr.getByteBuffer(record.StringOffset.intValue(), record.DataOffset.intValue() - record.StringOffset.intValue());
                    strings.position(0);
                    CharBuffer stringsBuf = strings.asCharBuffer();
                    System.out.println("STRINGS["+record.NumStrings.intValue()+"]: \n" + stringsBuf.toString());
                }
                // BYTE  Data[]
                {
                    ByteBuffer data = pevlr.getByteBuffer(record.DataOffset.intValue(), record.DataLength.intValue());
                    data.position(0);
                    CharBuffer dataBuf = data.asCharBuffer();
                    System.out.println("DATA: \n" + dataBuf.toString());
                }
                // CHAR  Pad[]
                // DWORD Length;

                dwRead -= record.Length.intValue();
                pevlr = pevlr.share(record.Length.intValue());
            }
        }
        assertTrue(rc == W32Errors.ERROR_HANDLE_EOF);
        assertTrue(com.sun.jna.platform.win32.Advapi32.INSTANCE.CloseEventLog(h));        
    }


    private static void assertTrue(boolean getOldestEventLogRecord) {

    }

}

示例输出(最后一个事件日志):

------------------------------------------------------------
570. 26957 Event ID: 107 SID: 0
SOURCE NAME: 
Report Server Windows Service (VOSTRO)
COMPUTER NAME: 
CVS
SID: 
N/A
STRINGS[1]: 
Report Server Windows Service (VOSTRO)
DATA: 

备注:

我已将 lpBuffer 设置为 0x7FFFF 字节的最大大小。

它使用WinNT.EVENTLOG_SEEK_READ模式,记录编号偏移 dwRecordOffset 从最早的记录编号开始。

ReadEventLog()方法返回零并且其GetLastError()返回W32Errors.ERROR_INSUFFICIENT_BUFFER时,while循环将中断。

应使用简短读取事件ID,以获取正确的值:record.EventID.shortValue()