2011-04-22 47 views
3

我一直在研究使用API​​從Windows事件日誌中獲取事件的應用程序。目前我被困在指針偏移處。我使用的具體結構是EVENTLOGRECORD(請參閱:http://msdn.microsoft.com/en-us/library/aa363646(v=vs.85).aspx)。我的C#結構定義爲:在C中使用指針偏移量#

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)] 
internal struct EVENTLOGRECORD 
{ 
    internal UInt32 Length; 
    internal UInt32 Reserved; 
    internal UInt32 RecordNumber; 
    internal UInt32 TimeGenerated; 
    internal UInt32 TimeWritten; 
    internal UInt32 EventID; 
    internal UInt16 EventType; 
    internal UInt16 NumStrings; 
    internal UInt16 EventCategory; 
    internal UInt16 ReservedFlags; 
    internal UInt32 ClosingRecordNumber; 
    internal UInt32 StringOffset; 
    internal UInt32 UserSidLength; 
    internal UInt32 UserSidOffset; 
    internal UInt32 DataLength; 
    internal UInt32 DataOffset; 
} 
作爲

我ReadEventLog函數聲明:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "ReadEventLog")] 
internal static extern Boolean ReadEventLog(IntPtr hEventLog, EVT_READ_FLAGS dwReadFlags, UInt32 dwRecordOffset, IntPtr lpBuffer, UInt32 nNumberOfBytesToRead, out UInt32 pnBytesRead, out UInt32 pnMinNumberOfBytesNeeded); 

我能夠得到填充數據的結構,我可以用得到SOURCENAME和計算機名段IntPtr.Add。例如:

IntPtr pSrc = IntPtr.Add(pRecord, Marshal.SizeOf(typeof(EVENTLOGRECORD))); 
string sSrc = Marshal.PtrToStringAuto(pSrc); 
Console.WriteLine("source: {0}\n", sSrc); 

IntPtr pComp = IntPtr.Add(pSrc, (sSrc.Length * 2) + 2); 
string sComp = Marshal.PtrToStringAuto(pComp); 
Console.WriteLine("computer: {0}\n", sComp); 

我的問題是試圖從結構中獲取字符串部分。我似乎無法弄清楚什麼是正確的偏移量。我可以用C++來完成,但我似乎無法使它在C#中工作。以下是我在C使用的一個片段++(ELR是(EVENTLOGRECORD *)pRecord):

char* strings = (LPSTR)((LPBYTE) elr + elr->StringOffset); 
while (elr->NumStrings) 
{ 
    wprintf(L"String: %s\n", strings); 
    strings += (wcslen((wchar_t*)strings) * sizeof(wchar_t)) + sizeof(wchar_t); 
    elr->NumStrings--; 
} 

希望有人可以幫助解釋,我錯過了什麼。我也很好奇,如果有任何替代IntPtr.Add,因爲需要.NET 4.0。我不是以任何方式調用p /的專家。謝謝。

+0

這是做爲練習嗎?爲什麼不使用System.Diagnostics.EventLog類讀取條目? – Tom 2011-04-22 17:23:43

+3

不。實際上,它是由於.NET框架中的錯誤而導致的:https://connect.microsoft.com/VisualStudio/feedback/details/654644/eventlog-entrywritten-and-event-log-overwrite-as -needed-problems 我提交了一個,顯然這確實是一個問題。否則,我會遍佈EventLog類。這很容易。 – Deviation 2011-04-22 17:25:04

+0

我不明白爲什麼一個寫入錯誤(它看起來是Connect鏈接)會阻止你使用內置的類從日誌中讀取事件。 – 2011-04-22 17:56:46

回答

1

一段時間後,從編碼到使大腦清醒了,我終於有了一個解決方案。我錯誤地將偏移量設置得太大,因爲我將struct(EVENTLOGRECORD)的大小添加到StringOffset中,然後將其添加到現有對象中。我真正需要做的是將偏移量添加到現有的IntPtr(pRecord)。不知道爲什麼沒有點擊之前。

所以簡單地做:

int offset = ((int)(((EVENTLOGRECORD)o).StringOffset)); 
IntPtr pStrings = IntPtr.Add(pRecord, offset); 
string sString = Marshal.PtrToStringAuto(pStrings); 
Console.WriteLine("string : {0}\n", sString); 

..是夠得着的字符串。謝謝你的幫助。我顯然沒有表示將建議標記爲有用。猜猜我只是需要時間離開這個。

1

它使用Marshal.PtrToStructure()到數據塊的第一部分複製到EVENTLOGRECORD,那麼你應該能夠只是做一些事情,如:

EVENTLOGRECORD record; 
... Copy the ptr into record ... 
IntPtr pStrings = IntPtr.Add(pRecord, (record.StringOffset * 2)); 

我很樂意爲你做這件事,但我懶得做所有其他p/invoke位,只要能夠進行ReadEventLog調用即可。

+0

我可以使用ReadEventLog填寫結構良好。我也用: 'IntPtr pRecord = IntPtr.Zero; object o = Marshal.PtrToStructure(pRecord,typeof(EVENTLOGRECORD));' 我只是無法看到所有的字符串。 EVENTLOGRECORD中的NumStrings通常會指示多於一個。 – Deviation 2011-04-22 17:46:28

0

提問可能太遲了。爲什麼你不使用.NET的System.Diagnostics.EventLog類? 據我所見,你有EventLog類的問題。你有沒有嘗試EventLogReader類,它適用於Windows版本Vista和更高版本?

使用反射器,您還可以瞭解他們如何進行編組。看起來,這是不可能讓編組完成工作的。他們會將數據讀入一個簡單的字節數組中,並將其存儲在EventLogEntry類中,該類可以直接從字節數組中讀取所需的數據。

要讀取它們在EventLogEntry類中執行的替換字符串。 databuf成員是來自本機ReadEventLog調用的字節數組。

[MonitoringDescription("LogEntryReplacementStrings")] 
public string[] ReplacementStrings 
{ 
    get 
    { 
     string[] strArray = new string[this.ShortFrom(this.dataBuf, this.bufOffset + 0x1a)]; 
     int index = 0; 
     int offset = this.bufOffset + this.IntFrom(this.dataBuf, this.bufOffset + 0x24); 
     StringBuilder builder = new StringBuilder(); 
     while (index < strArray.Length) 
     { 
      char ch = this.CharFrom(this.dataBuf, offset); 
      if (ch != '\0') 
      { 
       builder.Append(ch); 
      } 
      else 
      { 
       strArray[index] = builder.ToString(); 
       index++; 
       builder = new StringBuilder(); 
      } 
      offset += 2; 
     } 
     return strArray; 
    } 
} 

你的, 阿洛伊斯·克勞斯

+0

看到我上面的評論:https://connect.microsoft.com/VisualStudio/feedback/details/654644/eventlog-entrywritten-and-event-log-overwrite-as-needed-problems – Deviation 2011-04-22 17:39:37

+0

@Deviation - 事件日誌中一些不明確的錯誤入門寫作沒有理由不在框架源中尋找靈感來閱讀事件日誌條目。 Alois剛發佈的代碼只是做你想做的事情。 – 2011-04-22 17:54:55

+0

@威爾迪恩 - 一些隱晦的錯誤?如果您無法使用框架可靠地讀取事件,則必須以另一種方式進行處理。 EntryWritten事件有一個阻止它被可靠使用的錯誤。 我回復時沒有發佈他的代碼。我現在正在審查它是否能解決我遇到的問題。 – Deviation 2011-04-22 18:01:53