Работа со смещением указателя в C # - PullRequest
3 голосов
/ 22 апреля 2011

Я работал над приложением, которое использует API для получения событий из журнала событий Windows.Я застрял на смещении указателя в данный момент.Конкретной структурой, которую я использую, является EVENTLOGRECORD (см .: http://msdn.microsoft.com/en-us/library/aa363646(v=vs.85).aspx). Моя структура 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 и ComputerName с помощью 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);

Моя проблема заключается в попытке получить часть Strings из структуры.Я не могу понять, какие будут правильные смещения. Я могу сделать это в C ++, но я не могу заставить его работать в C #. Вот фрагмент того, что я использую в C ++ (elr is (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 / invoke любым способом. Спасибо.

Ответы [ 3 ]

1 голос
/ 26 апреля 2011

Через некоторое время после кодирования, чтобы очистить мозг, у меня наконец-то есть решение.Я неправильно делал смещение слишком большим, так как я брал размер структуры (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 голос
/ 22 апреля 2011

Если вы используете Marshal.PtrToStructure (), чтобы скопировать первую часть вашего блока данных в EVENTLOGRECORD, тогда вы сможете сделать что-то вроде:

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

Я был бы счастливчтобы это пошло вам на пользу, но мне лень делать все остальные биты p / invoke, которые позволяют выполнять вызов ReadEventLog.

0 голосов
/ 22 апреля 2011

Возможно, уже поздно спрашивать. Почему вы не используете класс * .NET System.Diagnostics.EventLog ? Насколько я вижу, у вас есть проблемы с классом EventLog. Вы пробовали класс EventLogReader , который работает для Windows Версии Vista и выше?

С помощью Reflector вы также можете узнать, как они выполняют сортировку. Похоже, что нельзя позволить маршаллеру сделать всю работу. Они читают данные в простой байтовый массив и сохраняют их в классе 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;
    }
}

С уважением, Алоис Краус

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...