2011-04-22 53 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