::ReadEventLog Problem

Acest forum este dedicat intrebarilor de Windows API, folosing C/C++
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

::ReadEventLog Problem

Post by Ovidiu Cucu » 19 Jul 2007, 15:27

S-a mai jucat cineva cu citire din event log-uri?
Eu ma joc acuma dar nu prea-mi ies toate pasientele. In general merge treaba, dar am probleme cand e vorba de "insertion strings" (care sunt folositi mai departe impreuna cu EventID in FormatMessage).
Functia ReadEventLog imi intoarce o inregistrare intr-o structura de genul:

Code: Select all

typedef struct _EVENTLOGRECORD { 
  DWORD  Length; 
  DWORD  Reserved; 
  DWORD  RecordNumber; 
  DWORD  TimeGenerated; 
  DWORD  TimeWritten; 
  DWORD  EventID; 
  WORD   EventType; 
  WORD   NumStrings; 
  WORD   EventCategory; 
  WORD   ReservedFlags; 
  DWORD  ClosingRecordNumber; 
  DWORD  StringOffset; 
  DWORD  UserSidLength; 
  DWORD  UserSidOffset; 
  DWORD  DataLength; 
  DWORD  DataOffset; 
  // 
  // Followed by: 
  // 
  // TCHAR SourceName[] 
  // TCHAR Computername[] 
  // SID   UserSid 
  // TCHAR Strings[] 
  // BYTE  Data[] 
  // CHAR  Pad[] 
  // DWORD Length; 
  // 
} EVENTLOGRECORD, *PEVENTLOGRECORD;
Mai intai am scris o functie care sa-mi dea marimea necesara a buffer-ului (pt. structura EVENTLOGRECORD si ce urmeaza dupa).

Code: Select all

DWORD CEventLog::GetReadEventLogBytesNeeded(DWORD dwRecord)
{
   DWORD dwRead  = 0, dwNeeded  = 0;
   ::ReadEventLog(m_handle, 
                  EVENTLOG_SEEK_READ|EVENTLOG_FORWARDS_READ,
                  dwRecord, m_pBuffer, 0, &dwRead, &dwNeeded);
   return dwNeeded;
}
Dupa care urmeaza functia care imi intoarce efectiv inregistrarea

Code: Select all

void CEventLog::GetRecord(DWORD dwRecord, LPBYTE& pBuffer)
{
   DWORD dwNeeded = GetReadEventLogBytesNeeded(dwRecord);
   if(dwNeeded > m_dwBuffSize)
   {
      m_dwBuffSize = dwNeeded + 64;
      delete []m_pBuffer;
      m_pBuffer = new BYTE[m_dwBuffSize];
   }
   ::ZeroMemory(m_pBuffer, m_dwBuffSize);
   DWORD dwRead = 0;
   BOOL bRet = ::ReadEventLog(m_handle, 
                              EVENTLOG_SEEK_READ|EVENTLOG_FORWARDS_READ,
                              dwRecord, m_pBuffer, m_dwBuffSize, &dwRead, &dwNeeded);
   if(! bRet) /* Blah-blah Exception */;  
   pBuffer = m_pBuffer;
}
Problema e ca in continuare, cand NumStrings > 0 (exista insertion strings) si iau offset-ul dat de StringOffset (care pare bun pt. ca-mi da pozitia de dupa ComputerName si UserSid), gasesc acolo numai "carcalaci".
Am atasat si o poza (e selectata partea unde incep stringurile de insertie).

Are cineva vreo idee ce gresesc? (event log viewer-ul, de exemplu, afseaza corect deci nu se pune problema de inregistrari "damaged").
Attachments
InsertionStrings.gif
InsertionStrings.gif (15.77 KiB) Viewed 8165 times



User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: ::ReadEventLog Problem

Post by Marius Bancila » 19 Jul 2007, 16:51

Ai aruncat o privire peste articolul asta http://www.codeproject.com/system/sysevent.asp? S-ar putea sa-ti fie de ajutor.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 19 Jul 2007, 17:24

De uitat m-am uitat, chiar daca e scris cu picioarele (calu' de dar....).
Well, a facut ca mine, a luat offset-ul stringurilor (dat de membrul StringOffset al structurii), si de acolo a parsat stringurile de insertie delimitate de '\0' (numarul lor e dat de NumStrings).
Pacat numai ca, desi s-a compilat n-am putut sa si-l rulez (vrea nusce chestie), pentru comparatie.

Problema mea e ca in bufferul umplut de ReadEventLog, de la offset-ul StringOffset si pana la DataOffset nu vad decat carcalaci (am selectat acum mai clar in imaginea atasata mai sus). Am zis la un momentdat ca o fi UNICODE, dar nici asa nu pare.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 19 Jul 2007, 17:39

Si pe langa problema principala.

Conform specificatiilor (vezi structura EVENTLOGRECORD) primii patru bytes dau lungimea inregistrarii.
Mai sus avem 48 01 00 00 ceea ce "convertit" la un DWORD da 0x148 (328 in zecimal).
Tot conform specificatiilor, pe ultimii 4 bytes ar trebui sa am tot lungimea, dar vad cu totul altceva: EE FE EE FE.
Daca n-am mai spus repet :), ReadEventLog imi introarce TRUE, iar dwRead indica corect lungimea 328.

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: ::ReadEventLog Problem

Post by Marius Bancila » 19 Jul 2007, 18:50

Pai iti incepe asa FD FD FD FD. Aia e "no man's land". E folosita ca o zona de demilitare a memoriei alocata dinamic. Apoi urmeaza BAADF00D (in little endian). Aia desemneaza o zona alocate cu LocalAlloc, memorie fixa (LMEM_FIXED) dar care inca nu a fost scrisa. Apoi urmeaza AB AB AB... Aia e memorie alocata cu LocalAlloc. Ai cateva blocuri din astea. Apoi urmeaza FE EE EE EE...Aia e scris de HeapFree() ca sa indice a aia e o zona libera din heap. Poti citi mai multe aici: http://www.codeguru.com/Cpp/W-P/win32/t ... php/c9535/, desi sunt sigur ca sti chestiile astea.

Hai ca incerc sa arunc si eu o privire.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: ::ReadEventLog Problem

Post by Marius Bancila » 19 Jul 2007, 19:38

Uite, am facut chestia asta:

Code: Select all

#define BUFFER_SIZE 1024*64

class CEventLog
{
	DWORD	m_dwBuffSize;
	BYTE	m_pBuffer[BUFFER_SIZE];
	HANDLE	m_handle;

public:
	CEventLog(DWORD size): m_dwBuffSize(size), m_handle(NULL)
	{
	}

	~CEventLog()
	{
	}

	void Open()
	{
		m_handle = OpenEventLog( NULL, L"Application");
	}

	void Close()
	{
		if(m_handle)
			CloseEventLog(m_handle);
	}

	DWORD CEventLog::GetReadEventLogBytesNeeded(DWORD dwRecord)
	{
		DWORD dwRead  = 0, dwNeeded  = 0;
		if(0 == ::ReadEventLog(m_handle, 
			EVENTLOG_SEEK_READ|EVENTLOG_FORWARDS_READ,
			dwRecord, m_pBuffer, 0, &dwRead, &dwNeeded) &&
			ERROR_INSUFFICIENT_BUFFER == GetLastError())
			return dwNeeded;
		return 0;
	}

	void GetRecord(DWORD dwRecord)
	{
		DWORD dwNeeded = GetReadEventLogBytesNeeded(dwRecord);
		DWORD dwRead = 0;
		DWORD dwThisRecord = 0;

		EVENTLOGRECORD* pevlr = (EVENTLOGRECORD *) &m_pBuffer;

		GetOldestEventLogRecord(m_handle, &dwThisRecord);

		if(ReadEventLog(m_handle,
			EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ, 
			dwRecord,
			pevlr,
			m_dwBuffSize,
			&dwRead,
			&dwNeeded))
		{
			while (dwRead > 0) 
			{ 
				printf("%03d  Event ID: 0x%08X  Event type: ", 
					dwThisRecord++, pevlr->EventID); 

				switch(pevlr->EventType)
				{
				case EVENTLOG_ERROR_TYPE:
					printf("EVENTLOG_ERROR_TYPE\t  ");
					break;
				case EVENTLOG_WARNING_TYPE:
					printf("EVENTLOG_WARNING_TYPE\t  ");
					break;
				case EVENTLOG_INFORMATION_TYPE:
					printf("EVENTLOG_INFORMATION_TYPE  ");
					break;
				case EVENTLOG_AUDIT_SUCCESS:
					printf("EVENTLOG_AUDIT_SUCCESS\t  ");
					break;
				case EVENTLOG_AUDIT_FAILURE:
					printf("EVENTLOG_AUDIT_FAILURE\t  ");
					break;
				default:
					printf("Unknown ");
					break;
				}

				printf("Event source: %s\n", 
					(LPSTR) ((LPBYTE) pevlr + sizeof(EVENTLOGRECORD))); 

				dwRead -= pevlr->Length; 
				pevlr = (EVENTLOGRECORD *) 
					((LPBYTE) pevlr + pevlr->Length); 
			} 

			pevlr = (EVENTLOGRECORD *) &m_pBuffer; 
		} 
	}

};

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	CEventLog log(BUFFER_SIZE);
	BYTE* buffer = NULL;

	log.Open();

	log.GetRecord(2);

	log.Close();

	return 0;
}
Merge atata timp cat nu alloci memorie in mod dinamic pentru buffer-ul ala. Cand ai facut-o, gata, nu mai merge...
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 19 Jul 2007, 19:42

Mersi mult, Marius!
La urma i-am dat de capat. Nu am reusit pana nu am facut ca Baba Safta (adica s-o iau babeste) sa scriu din nou codul intr-o aplicatie de test, sa schimb pana si modul de alocare cu new in GlobalAlloc si alte giumbuslucuri si degeaba. Eh, se mai schimbau ei carcalacii, vorba ta cu cei din articol... :)
Eh... totul pornea de la un cast aiurea, undeva unde copiam bufferul. Tii minte ca am zis ca primii patru octeti au in componenta lungimea inregistrarii...

Code: Select all

void CLogRecord::Copy(const LPBYTE pBuffer)
{
   Clear();
   if(NULL != pBuffer)
   {
      // const DWORD dwLength = (DWORD)(*pBuffer); // stupid.
      const DWORD dwLength = *((LPDWORD)pBuffer); // correct.
      m_pBuffer = (LPBYTE)::GlobalAlloc(GPTR, dwLength);
      memcpy(m_pBuffer, pBuffer, dwLength);
   }
}
Stupid, isn't it? Numa bun de tocat nervii o zi intreaga. Deh, se mai intampla si la ai de se dau tari in pointeri. :D

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: ::ReadEventLog Problem

Post by Marius Bancila » 19 Jul 2007, 23:18

Si sti de ce nu merge cu new, numai cu GlobalAlloc sau buffer pe stack? Zice undeva ca nu poate fi alocata memoria cu altceva? Nu am remarcat asta in MSDN.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 20 Jul 2007, 00:46

Ba merge si cu new. Am zis mai sus: era o incercare tip "Baba Safta", in disperare...
OK. Acum am rezolvat toate. Am lasat cu GlobalAlloc ca-i mai trendy. ;)

User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: ::ReadEventLog Problem

Post by Marius Bancila » 20 Jul 2007, 08:44

Eu cand alocam cu new imi intorce eroare: bad parameter. :( Since, n-am avut timp sa studiez prea mult de ce.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 20 Jul 2007, 17:15

Marius Bancila wrote:Eu cand alocam cu new imi intorce eroare: bad parameter. :( Since, n-am avut timp sa studiez prea mult de ce.
OK, o sa studiez eu problema. Tokmai am terminat un release la project si am o mica "fereastra". :)

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: ::ReadEventLog Problem

Post by Ovidiu Cucu » 21 Jul 2007, 19:22

Marius, desi am mai intalnit la functii similare eroarea "bad parameter" nu am reusit s-o reproduc in cazul lui ReadEventLog.
Merge si cu buffer-ul alocat cu new.
Ai mai jos un exemplu de test simplificat la maximum (ca sa incapa pe forum [:)]) pe care l-am testat atat pe VC++6.0 cat si pe 2005.

Code: Select all

#include <windows.h>

int main()
{
   HANDLE hLog = ::OpenEventLogA(NULL, "Application");
   if(NULL != hLog)
   {
      DWORD dwRecord = 0;
      if(::GetOldestEventLogRecord(hLog, &dwRecord))
      {
         DWORD dwFlags = EVENTLOG_SEEK_READ|EVENTLOG_FORWARDS_READ;
         DWORD dwToRead = 1, dwRead = 0, dwNeeded = 0;
         // see how many bytes are needed to get the record
         BYTE btDummy = 0;
         ::ReadEventLogA(hLog, dwFlags, dwRecord, &btDummy, 
                                               dwToRead, &dwRead, &dwNeeded);
         dwToRead = dwNeeded;
         LPBYTE  lpBuffer = new BYTE[dwToRead];
         // get the record
         if(::ReadEventLogA(hLog, dwFlags, dwRecord, lpBuffer, 
                                               dwToRead, &dwRead, &dwNeeded))
         {
            ::MessageBoxA(NULL, "Success", "Test", MB_OK);
         }
         delete[] lpBuffer;
      }
      ::CloseEventLog(hLog);
   }
   return 0;
}
BTW. Am reusit intre timp sa fac sa mearga si demo-ul din articolul pe care mi l-ai link-uit mai devreme.
Era un exemplu tipic de "aplicatie WOMM"... :) ;)

Post Reply