程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何讀寫WINDOWS 2000的日志

如何讀寫WINDOWS 2000的日志

編輯:關於VC++

一些大型應用程序會把他們的一些事件寫到日志裡面去,比如sql server,norton,iis等.我google了一下,網上關於這方面的資料並不是很完整,於是整理加工了一下. 下面是我看msdn,用google及自己摸索得到的一點體會,共享.

一.注冊事件源.(需以administrator登陸本機才行)

你需要為你的應用程序注冊一個事件源,以表明那些是屬於你應用程序的事件.

HKEY hk;
  ULONG disposition, allowed;
  char szName[256];
  strcpy(szName,"SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\");
  strcat(szName,"CMCard");
  if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,szName,0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,
    NULL,&hk,&disposition))//為事件源建一個鍵
  { 
    printf("Unable to create registry key");
      return;
  }
  strcpy (szName,"%SystemRoot%\\System\\MYDLL.DLL");
  if(RegSetValueEx(hk,"EventMessageFile",0,REG_EXPAND_SZ,(LPBYTE)szName,strlen(szName)+1))
  {//為事件源指定一個解釋事件的事件dll.
    printf("Unable to create/set registryvalue (message DLL name)");
    return;
  }
  allowed=EVENTLOG_ERROR_TYPE|EVENTLOG_WARNING_TYPE|EVENTLOG_INFORMATION_TYPE;
  if (RegSetValueEx(hk,"TypesSupported",0,REG_DWORD,(LPBYTE)&allowed,sizeof(DWORD)))
  {//為事件源指定類型
    printf("Unable to create/set registry value (message types)");
    return;
  }
  RegCloseKey(hk);

二.編寫事件dll.(用於解釋事件id表示的內容)

用mc.exe(vc自帶)編譯一個*.mc文件,生成*.h,*.rc,*.bin,再用他們生成一個資源dll(用vc生成一個空

win32dll框架,把他們加進來編譯),放system目錄下.

下面是一個mc文件的樣板:

;//begin==============================================================
;#ifndef __CMCARD_H__
;#define __CMCARD_H__
LanguageNames=(Chinese=2052:MSG0052)
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
        Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
        Warning=0x2:STATUS_SEVERITY_WARNING
        Error=0x3:STATUS_SEVERITY_ERROR
       )
MessageId=1000 Severity=Success SymbolicName=CM_CARD_STATUS_OK
Language=Chinese
CMCard的狀態良好.
.
MessageId=1001 Severity=Success SymbolicName=CM_CARD_STATUS_BED
Language=Chinese
CMCard出錯了,原因可能是%1.
.
;#endif //__CMCARD_H__
;//end================================================================

說明:默認的語言是英語,此時"LanguageNames="那句可以省略;

%1表示從ReportEvent傳來的參數;

注意注釋時";"與";//"的不同用法.mc編譯器會忽略";"後面的字符,但會把他們寫到*.h文件裡.

三.寫日志的方法.

//vc
BOOL syslog(DWORD dwID,char*str,WORD wType)//參數:事件id;事件附加信息;事件類型
{
  HANDLE hd=RegisterEventSource(NULL,"CMCard");//指定/打開事件源
  char* buff[1];
  buff[0]=str;
  int i;
  if(hd){
    i=ReportEvent(hd,wType,0,dwID,NULL,1,0,(LPCTSTR*)buff,NULL);//寫日志
    DeregisterEventSource(hd);//關閉事件源
    if(i)return TRUE;
  }
  return FALSE;
}
''vb
Private Declare Function ReportEvent Lib "advapi32" Alias "ReportEventA" (ByVal hEventLog As Long, _
  ByVal wType As Long, ByVal wCategory As Long, ByVal dwEventID As Long, ByVal lpUserSid As Long, _
  ByVal wNumStrings As Long, ByVal dwDataSize As Long, lpStrings As Any, lpRawData As Any) As Long
''注意這個聲明,與api text viewer的是不同的.注意As Any的妙用.
Function sysLog(byval lngID as long,byval strMsg As String,byval lngType as long) As Boolean
  Dim hd As Long
  Dim ret As Integer
  hd = RegisterEventSource("", "CMCard")
  If hd <> 0 Then
    ret = ReportEvent(hd, lngType, 0, lngID, 0&, 1, 0, strMsg, 0)
    DeregisterEventSource hd
  End If
  If ret <> 0 Then
    sysLog = True
  Else: sysLog = False
  End If
End Function

四 .讀日志的例子.

void CEventDlg::OnButton3()
{//參考http://www.codeproject.com/system/sysevent.asp
  HANDLE hdle;
  EVENTLOGRECORD *ptr;
  BYTE buff[4096];
  DWORD read_len, next_len;
  ptr=(EVENTLOGRECORD *)&buff;
  hdle=OpenEventLog("", "Application");// System
  if (hdle==NULL)
  {
    MessageBox("打開日志失敗");
  }
  else
  {
    long mRet;
    char lpszSourceName[255]={0};
    char lpszComputerName[255]={0};
    unsigned uStepOfString;
    char* pStrings;
    char szExpandedString[1024]={0};
    while(ReadEventLog(hdle,EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
      1,ptr,sizeof(buff),&read_len,&next_len))
    {
      mRet=ptr->EventID;//事件id
      mRet=ptr->EventType;//事件類型
      mRet=ptr->TimeWritten;//
      mRet=ptr->NumStrings;//
      mRet=ptr->Length;//
      mRet=sizeof(EVENTLOGRECORD);
      strcpy(lpszSourceName, (LPTSTR)((LPBYTE)ptr +mRet));//事件源
      mRet+= strlen(lpszSourceName) + 1;
      strcpy(lpszComputerName, (LPTSTR)((LPBYTE)ptr + mRet));//機器名
      mRet+= strlen(lpszComputerName) + 1;
      if(ptr->UserSidLength>0){;}//
      mRet=ptr->DataOffset-ptr->StringOffset;
      if(mRet>0)//事件描述
      {
        pStrings=new char[mRet];
        memcpy(pStrings,(LPBYTE)ptr+ptr->StringOffset,mRet);
        uStepOfString=0;
        for(int x=0;x<ptr->NumStrings;x++)
        {
          if(x==0)
          {
            strcpy(szExpandedString, (TCHAR *)pStrings + uStepOfString);
            if(x<(UINT)ptr->NumStrings - 1)strcat(szExpandedString, ",");
          }
          else strcat(szExpandedString, pStrings + uStepOfString);
          uStepOfString = strlen(pStrings + uStepOfString) + 1;
        }
        delete [] pStrings;
      }
      MessageBox(lpszSourceName,szExpandedString);
    }
    CloseEventLog(hdle);
  }
}

五.源代碼的使用與運行結果

本文附帶的示例工程對WIN2K日志的讀寫進行了演示,使用時先編譯mydll,並拷貝到system目錄下,然後編譯event工程。運行結果可以使用事件查看器查看:

假如在指定的位置沒有找到mydll,則會顯示:

事件 ID ( 1001 )的描述(在資源( CMCard )中)無法找到。本地計算機可能沒有必要的注冊信息或消息 DLL 文件來從遠端計算機顯示消息。部分事件包含了下列信息: king_koo

Hello!.

六.後記

以上演示了讀寫win2k日志的基本方法,重在應用.想知道更理論/更詳盡的東西,就只有再認真研究msdn了.

另:讀日志好麻煩,誰知道更簡捷的方法麻煩告訴我一聲.歡迎指點/批評([email protected])

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved