/*
- * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
+ * LICENSE: GPL - See COPYING in the top level directory
* FILE: services/eventlog/eventlog.c
* PURPOSE: Event logging service
- * PROGRAMMERS: Saveliy Tretiakov (saveliyt@mail.ru)
- * Eric Kohl
+ * COPYRIGHT: Copyright 2002 Eric Kohl
+ * Copyright 2005 Saveliy Tretiakov
*/
+/* INCLUDES *****************************************************************/
#include "eventlog.h"
-VOID CALLBACK ServiceMain(DWORD argc, LPTSTR *argv);
+/* GLOBALS ******************************************************************/
-SERVICE_TABLE_ENTRY ServiceTable[2] =
+static VOID CALLBACK ServiceMain(DWORD, LPWSTR *);
+static WCHAR ServiceName[] = L"EventLog";
+static SERVICE_TABLE_ENTRYW ServiceTable[2] =
{
- {L"EventLog", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
- {NULL, NULL}
+ { ServiceName, ServiceMain },
+ { NULL, NULL }
};
+SERVICE_STATUS ServiceStatus;
+SERVICE_STATUS_HANDLE ServiceStatusHandle;
+
+BOOL onLiveCD = FALSE; // On livecd events will go to debug output only
HANDLE MyHeap = NULL;
-PLOGFILE SystemLog = NULL;
-VOID CALLBACK ServiceMain(DWORD argc, LPTSTR *argv)
+/* FUNCTIONS ****************************************************************/
+
+static VOID
+UpdateServiceStatus(DWORD dwState)
+{
+ ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ServiceStatus.dwCurrentState = dwState;
+ ServiceStatus.dwControlsAccepted = 0;
+ ServiceStatus.dwWin32ExitCode = 0;
+ ServiceStatus.dwServiceSpecificExitCode = 0;
+ ServiceStatus.dwCheckPoint = 0;
+
+ if (dwState == SERVICE_START_PENDING ||
+ dwState == SERVICE_STOP_PENDING ||
+ dwState == SERVICE_PAUSE_PENDING ||
+ dwState == SERVICE_CONTINUE_PENDING)
+ ServiceStatus.dwWaitHint = 10000;
+ else
+ ServiceStatus.dwWaitHint = 0;
+
+ SetServiceStatus(ServiceStatusHandle,
+ &ServiceStatus);
+}
+
+static DWORD WINAPI
+ServiceControlHandler(DWORD dwControl,
+ DWORD dwEventType,
+ LPVOID lpEventData,
+ LPVOID lpContext)
+{
+ DPRINT("ServiceControlHandler() called\n");
+
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ DPRINT(" SERVICE_CONTROL_STOP received\n");
+ UpdateServiceStatus(SERVICE_STOPPED);
+ return ERROR_SUCCESS;
+
+ case SERVICE_CONTROL_PAUSE:
+ DPRINT(" SERVICE_CONTROL_PAUSE received\n");
+ UpdateServiceStatus(SERVICE_PAUSED);
+ return ERROR_SUCCESS;
+
+ case SERVICE_CONTROL_CONTINUE:
+ DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
+ UpdateServiceStatus(SERVICE_RUNNING);
+ return ERROR_SUCCESS;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
+ SetServiceStatus(ServiceStatusHandle,
+ &ServiceStatus);
+ return ERROR_SUCCESS;
+
+ case SERVICE_CONTROL_SHUTDOWN:
+ DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
+ UpdateServiceStatus(SERVICE_STOPPED);
+ return ERROR_SUCCESS;
+
+ default :
+ DPRINT1(" Control %lu received\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+
+static DWORD
+ServiceInit(VOID)
{
HANDLE hThread;
NULL,
0,
NULL);
-
- if(!hThread) DPRINT("Can't create PortThread\n");
- else CloseHandle(hThread);
-
+
+ if (!hThread)
+ {
+ DPRINT("Can't create PortThread\n");
+ return GetLastError();
+ }
+ else
+ CloseHandle(hThread);
+
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)
0,
NULL);
- if(!hThread) DPRINT("Can't create RpcThread\n");
- else CloseHandle(hThread);
+ if (!hThread)
+ {
+ DPRINT("Can't create RpcThread\n");
+ return GetLastError();
+ }
+ else
+ CloseHandle(hThread);
+
+ return ERROR_SUCCESS;
+}
+
+
+static VOID CALLBACK
+ServiceMain(DWORD argc,
+ LPWSTR *argv)
+{
+ DWORD dwError;
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ DPRINT("ServiceMain() called\n");
+
+ ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
+ ServiceControlHandler,
+ NULL);
+ if (!ServiceStatusHandle)
+ {
+ dwError = GetLastError();
+ DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
+ return;
+ }
+
+ UpdateServiceStatus(SERVICE_START_PENDING);
+
+ dwError = ServiceInit();
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT("Service stopped (dwError: %lu\n", dwError);
+ UpdateServiceStatus(SERVICE_START_PENDING);
+ }
+ else
+ {
+ DPRINT("Service started\n");
+ UpdateServiceStatus(SERVICE_RUNNING);
+
+ LogfReportEvent(EVENTLOG_INFORMATION_TYPE,
+ 0,
+ EVENT_EventlogStarted);
+ }
+
+ DPRINT("ServiceMain() done\n");
+}
+
+
+PLOGFILE LoadLogFile(HKEY hKey, WCHAR * LogName)
+{
+ DWORD MaxValueLen, ValueLen, Type, ExpandedLen;
+ WCHAR *Buf = NULL, *Expanded = NULL;
+ LONG Result;
+ PLOGFILE pLogf;
+
+ DPRINT("LoadLogFile: %S\n", LogName);
+
+ RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &MaxValueLen, NULL, NULL);
+
+ Buf = HeapAlloc(MyHeap, 0, MaxValueLen);
+ if (!Buf)
+ {
+ DPRINT1("Can't allocate heap!\n");
+ return NULL;
+ }
+
+ ValueLen = MaxValueLen;
+
+ Result = RegQueryValueEx(hKey,
+ L"File",
+ NULL,
+ &Type,
+ (LPBYTE) Buf,
+ &ValueLen);
+ if (Result != ERROR_SUCCESS)
+ {
+ DPRINT1("RegQueryValueEx failed: %d\n", GetLastError());
+ HeapFree(MyHeap, 0, Buf);
+ return NULL;
+ }
+
+ if (Type != REG_EXPAND_SZ && Type != REG_SZ)
+ {
+ DPRINT1("%S\\File - value of wrong type %x.\n", LogName, Type);
+ HeapFree(MyHeap, 0, Buf);
+ return NULL;
+ }
+
+ ExpandedLen = ExpandEnvironmentStrings(Buf, NULL, 0);
+ Expanded = HeapAlloc(MyHeap, 0, ExpandedLen * sizeof(WCHAR));
+ if (!Expanded)
+ {
+ DPRINT1("Can't allocate heap!\n");
+ HeapFree(MyHeap, 0, Buf);
+ return NULL;
+ }
+
+ ExpandEnvironmentStrings(Buf, Expanded, ExpandedLen);
+
+ DPRINT("%S -> %S\n", Buf, Expanded);
+
+ pLogf = LogfCreate(LogName, Expanded);
+
+ if (pLogf == NULL)
+ {
+ DPRINT1("Failed to create %S!\n", Expanded);
+ }
+
+ HeapFree(MyHeap, 0, Buf);
+ HeapFree(MyHeap, 0, Expanded);
+ return pLogf;
}
+BOOL LoadLogFiles(HKEY eventlogKey)
+{
+ LONG result;
+ DWORD MaxLognameLen, LognameLen;
+ WCHAR *Buf = NULL;
+ INT i;
+ PLOGFILE pLogFile;
+
+ RegQueryInfoKey(eventlogKey,
+ NULL, NULL, NULL, NULL,
+ &MaxLognameLen,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ MaxLognameLen++;
+
+ Buf = HeapAlloc(MyHeap, 0, MaxLognameLen * sizeof(WCHAR));
+
+ if (!Buf)
+ {
+ DPRINT1("Error: can't allocate heap!\n");
+ return FALSE;
+ }
+
+ i = 0;
+ LognameLen = MaxLognameLen;
+
+ while (RegEnumKeyEx(eventlogKey,
+ i,
+ Buf,
+ &LognameLen,
+ NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+ {
+ HKEY SubKey;
+
+ DPRINT("%S\n", Buf);
+
+ result = RegOpenKeyEx(eventlogKey, Buf, 0, KEY_ALL_ACCESS, &SubKey);
+ if (result != ERROR_SUCCESS)
+ {
+ DPRINT1("Failed to open %S key.\n", Buf);
+ HeapFree(MyHeap, 0, Buf);
+ return FALSE;
+ }
+
+ pLogFile = LoadLogFile(SubKey, Buf);
+ if (pLogFile != NULL)
+ {
+ DPRINT("Loaded %S\n", Buf);
+ LoadEventSources(SubKey, pLogFile);
+ }
+ else
+ {
+ DPRINT1("Failed to load %S\n", Buf);
+ }
+
+ RegCloseKey(SubKey);
+ LognameLen = MaxLognameLen;
+ i++;
+ }
+
+ HeapFree(MyHeap, 0, Buf);
+ return TRUE;
+}
-int main(int argc, char *argv[])
+INT wmain()
{
- WCHAR SysLogPath[MAX_PATH];
- MyHeap = HeapCreate(0, 1024*256, 0);
-
- if(MyHeap==NULL)
- {
- DbgPrint("EventLog: FATAL ERROR, can't create heap.\n");
- return 1;
- }
-
- /*
- This will be fixed in near future
- */
-
- GetWindowsDirectory(SysLogPath, MAX_PATH);
- lstrcat(SysLogPath, L"\\system32\\config\\SysEvent.evt");
-
- SystemLog = LogfCreate(L"System", SysLogPath);
-
- if(SystemLog == NULL)
- {
- DbgPrint("EventLog: FATAL ERROR, can't create %S\n", SysLogPath);
- HeapDestroy(MyHeap);
- return 1;
- }
+ WCHAR LogPath[MAX_PATH];
+ INT RetCode = 0;
+ LONG result;
+ HKEY elogKey;
+
+ LogfListInitialize();
+ InitEventSourceList();
+
+ MyHeap = HeapCreate(0, 1024 * 256, 0);
+
+ if (!MyHeap)
+ {
+ DPRINT1("FATAL ERROR, can't create heap.\n");
+ RetCode = 1;
+ goto bye_bye;
+ }
+
+ GetWindowsDirectory(LogPath, MAX_PATH);
+
+ if (GetDriveType(LogPath) == DRIVE_CDROM)
+ {
+ DPRINT("LiveCD detected\n");
+ onLiveCD = TRUE;
+ }
+ else
+ {
+ result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
+ 0,
+ KEY_ALL_ACCESS,
+ &elogKey);
+
+ if (result != ERROR_SUCCESS)
+ {
+ DPRINT1("Fatal error: can't open eventlog registry key.\n");
+ RetCode = 1;
+ goto bye_bye;
+ }
+
+ LoadLogFiles(elogKey);
+ }
StartServiceCtrlDispatcher(ServiceTable);
- LogfClose(SystemLog);
- HeapDestroy(MyHeap);
+ bye_bye:
+ LogfCloseAll();
+
+ if (MyHeap)
+ HeapDestroy(MyHeap);
- return 0;
+ return RetCode;
}
-VOID EventTimeToSystemTime(DWORD EventTime,
- SYSTEMTIME *pSystemTime)
+VOID EventTimeToSystemTime(DWORD EventTime, SYSTEMTIME * pSystemTime)
{
- SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
- FILETIME ftLocal;
- union {
- FILETIME ft;
- ULONGLONG ll;
- } u1970, uUCT;
-
- uUCT.ft.dwHighDateTime = 0;
- uUCT.ft.dwLowDateTime = EventTime;
- SystemTimeToFileTime(&st1970, &u1970.ft);
- uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
- FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
- FileTimeToSystemTime(&ftLocal, pSystemTime);
+ SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
+ FILETIME ftLocal;
+ union
+ {
+ FILETIME ft;
+ ULONGLONG ll;
+ } u1970, uUCT;
+
+ uUCT.ft.dwHighDateTime = 0;
+ uUCT.ft.dwLowDateTime = EventTime;
+ SystemTimeToFileTime(&st1970, &u1970.ft);
+ uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
+ FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
+ FileTimeToSystemTime(&ftLocal, pSystemTime);
}
-VOID SystemTimeToEventTime(SYSTEMTIME *pSystemTime,
- DWORD *pEventTime)
+VOID SystemTimeToEventTime(SYSTEMTIME * pSystemTime, DWORD * pEventTime)
{
- SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
- union {
- FILETIME ft;
- ULONGLONG ll;
- } Time, u1970;
-
- SystemTimeToFileTime(pSystemTime, &Time.ft);
- SystemTimeToFileTime(&st1970, &u1970.ft);
- *pEventTime = (Time.ll - u1970.ll) / 10000000;
+ SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
+ union
+ {
+ FILETIME ft;
+ ULONGLONG ll;
+ } Time, u1970;
+
+ SystemTimeToFileTime(pSystemTime, &Time.ft);
+ SystemTimeToFileTime(&st1970, &u1970.ft);
+ *pEventTime = (Time.ll - u1970.ll) / 10000000;
}
-VOID PRINT_HEADER(PFILE_HEADER header)
+VOID PRINT_HEADER(PEVENTLOGHEADER header)
{
- DPRINT("SizeOfHeader=%d\n",header->SizeOfHeader);
- DPRINT("Signature=0x%x\n",header->Signature);
- DPRINT("MajorVersion=%d\n",header->MajorVersion);
- DPRINT("MinorVersion=%d\n",header->MinorVersion);
- DPRINT("FirstRecordOffset=%d\n",header->FirstRecordOffset);
- DPRINT("EofOffset=0x%x\n",header->EofOffset);
- DPRINT("NextRecord=%d\n",header->NextRecord);
- DPRINT("OldestRecord=%d\n",header->OldestRecord);
- DPRINT("unknown1=0x%x\n",header->unknown1);
- DPRINT("unknown2=0x%x\n",header->unknown2);
- DPRINT("SizeOfHeader2=%d\n",header->SizeOfHeader2);
- DPRINT("Flags: ");
- if(header->Flags & LOGFILE_FLAG1)DPRINT("LOGFILE_FLAG1 ");
- if(header->Flags & LOGFILE_FLAG2)DPRINT("| LOGFILE_FLAG2 ");
- if(header->Flags & LOGFILE_FLAG3)DPRINT("| LOGFILE_FLAG3 ");
- if(header->Flags & LOGFILE_FLAG4)DPRINT("| LOGFILE_FLAG4");
- DPRINT("\n");
+ DPRINT("HeaderSize = %d\n", header->HeaderSize);
+ DPRINT("Signature = 0x%x\n", header->Signature);
+ DPRINT("MajorVersion = %d\n", header->MajorVersion);
+ DPRINT("MinorVersion = %d\n", header->MinorVersion);
+ DPRINT("StartOffset = %d\n", header->StartOffset);
+ DPRINT("EndOffset = 0x%x\n", header->EndOffset);
+ DPRINT("CurrentRecordNumber = %d\n", header->CurrentRecordNumber);
+ DPRINT("OldestRecordNumber = %d\n", header->OldestRecordNumber);
+ DPRINT("MaxSize = 0x%x\n", header->MaxSize);
+ DPRINT("Retention = 0x%x\n", header->Retention);
+ DPRINT("EndHeaderSize = %d\n", header->EndHeaderSize);
+ DPRINT("Flags: ");
+ if (header->Flags & ELF_LOGFILE_HEADER_DIRTY) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
+ if (header->Flags & ELF_LOGFILE_HEADER_WRAP) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
+ if (header->Flags & ELF_LOGGFILE_LOGFULL_WRITTEN) DPRINT("| ELF_LOGGFILE_LOGFULL_WRITTEN ");
+ if (header->Flags & ELF_LOGFILE_ARCHIVE_SET) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
+ DPRINT("\n");
}
VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
{
- UINT i;
- WCHAR *str;
- SYSTEMTIME time;
-
- DPRINT("Length=%d\n", pRec->Length );
- DPRINT("Reserved=0x%x\n", pRec->Reserved );
- DPRINT("RecordNumber=%d\n", pRec->RecordNumber );
-
- EventTimeToSystemTime(pRec->TimeGenerated, &time);
- DPRINT("TimeGenerated=%d.%d.%d %d:%d:%d\n",
- time.wDay, time.wMonth, time.wYear,
- time.wHour, time.wMinute, time.wSecond);
-
- EventTimeToSystemTime(pRec->TimeWritten, &time);
- DPRINT("TimeWritten=%d.%d.%d %d:%d:%d\n",
- time.wDay, time.wMonth, time.wYear,
- time.wHour, time.wMinute, time.wSecond);
-
- DPRINT("EventID=%d\n", pRec->EventID );
-
- switch(pRec->EventType)
- {
- case EVENTLOG_ERROR_TYPE:
- DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
- break;
- case EVENTLOG_WARNING_TYPE:
- DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
- break;
- case EVENTLOG_INFORMATION_TYPE:
- DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
- break;
- case EVENTLOG_AUDIT_SUCCESS:
- DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
- break;
- case EVENTLOG_AUDIT_FAILURE:
- DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
- break;
- default:
- DPRINT("EventType = %x\n");
- }
-
- DPRINT("NumStrings=%d\n", pRec->NumStrings );
- DPRINT("EventCategory=%d\n", pRec->EventCategory);
- DPRINT("ReservedFlags=0x%x\n", pRec->ReservedFlags);
- DPRINT("ClosingRecordNumber=%d\n", pRec->ClosingRecordNumber);
- DPRINT("StringOffset=%d\n", pRec->StringOffset);
- DPRINT("UserSidLength=%d\n", pRec->UserSidLength);
- DPRINT("UserSidOffset=%d\n", pRec->UserSidOffset);
- DPRINT("DataLength=%d\n", pRec->DataLength);
- DPRINT("DataOffset=%d\n", pRec->DataOffset);
-
- DPRINT("SourceName: %S\n", (WCHAR *)(((PBYTE)pRec)+sizeof(EVENTLOGRECORD)));
- i = (lstrlenW((WCHAR *)(((PBYTE)pRec)+sizeof(EVENTLOGRECORD)))+1)*sizeof(WCHAR);
- DPRINT("ComputerName: %S\n", (WCHAR *)(((PBYTE)pRec)+sizeof(EVENTLOGRECORD)+i));
-
- if(pRec->StringOffset < pRec->Length && pRec->NumStrings){
- DPRINT("Strings:\n");
- str = (WCHAR*)(((PBYTE)pRec)+pRec->StringOffset);
- for(i = 0; i < pRec->NumStrings; i++)
- {
- DPRINT("[%d] %S\n", i, str);
- str = str+lstrlenW(str)+1;
- }
- }
-
- DPRINT("Length2=%d\n", *(PDWORD)(((PBYTE)pRec)+pRec->Length-4));
-}
+ UINT i;
+ WCHAR *str;
+ SYSTEMTIME time;
+
+ DPRINT("Length = %d\n", pRec->Length);
+ DPRINT("Reserved = 0x%x\n", pRec->Reserved);
+ DPRINT("RecordNumber = %d\n", pRec->RecordNumber);
+
+ EventTimeToSystemTime(pRec->TimeGenerated, &time);
+ DPRINT("TimeGenerated = %d.%d.%d %d:%d:%d\n",
+ time.wDay, time.wMonth, time.wYear,
+ time.wHour, time.wMinute, time.wSecond);
+
+ EventTimeToSystemTime(pRec->TimeWritten, &time);
+ DPRINT("TimeWritten = %d.%d.%d %d:%d:%d\n",
+ time.wDay, time.wMonth, time.wYear,
+ time.wHour, time.wMinute, time.wSecond);
+
+ DPRINT("EventID = %d\n", pRec->EventID);
+ switch (pRec->EventType)
+ {
+ case EVENTLOG_ERROR_TYPE:
+ DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
+ break;
+ case EVENTLOG_WARNING_TYPE:
+ DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
+ break;
+ case EVENTLOG_INFORMATION_TYPE:
+ DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
+ break;
+ case EVENTLOG_AUDIT_SUCCESS:
+ DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
+ break;
+ case EVENTLOG_AUDIT_FAILURE:
+ DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
+ break;
+ default:
+ DPRINT("EventType = %d\n", pRec->EventType);
+ }
+ DPRINT("NumStrings = %d\n", pRec->NumStrings);
+ DPRINT("EventCategory = %d\n", pRec->EventCategory);
+ DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags);
+ DPRINT("ClosingRecordNumber = %d\n", pRec->ClosingRecordNumber);
+ DPRINT("StringOffset = %d\n", pRec->StringOffset);
+ DPRINT("UserSidLength = %d\n", pRec->UserSidLength);
+ DPRINT("UserSidOffset = %d\n", pRec->UserSidOffset);
+ DPRINT("DataLength = %d\n", pRec->DataLength);
+ DPRINT("DataOffset = %d\n", pRec->DataOffset);
+ DPRINT("SourceName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD)));
+
+ i = (lstrlenW((WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD))) + 1) *
+ sizeof(WCHAR);
+
+ DPRINT("ComputerName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD) + i));
+
+ if (pRec->StringOffset < pRec->Length && pRec->NumStrings)
+ {
+ DPRINT("Strings:\n");
+ str = (WCHAR *) (((PBYTE) pRec) + pRec->StringOffset);
+ for (i = 0; i < pRec->NumStrings; i++)
+ {
+ DPRINT("[%d] %S\n", i, str);
+ str = str + lstrlenW(str) + 1;
+ }
+ }
+
+ DPRINT("Length2 = %d\n", *(PDWORD) (((PBYTE) pRec) + pRec->Length - 4));
+}