I have always thought of using .log to debug programs, I have made one a few days ago, which can be used in VC and BCB. The following is the effect of the program run, when I debug a service program, generate a .log log file, record some information related to the startup and closing service procedure ...
[Source path & filename:] E: / Microsoft / Desktop / Simple_Service_02/##simple_service.log[9844796] Record Start At Date: 2003.08.06 & Time: 16:19:25.
[9844796] _SIMPLE_SERVICE_07 Winmain Start [9844796] Winnt system is available! [9844796] CommandLine by Following. [9844796] E: / Microsoft / Desktop / Simple_Service_02/#simple_Service.exe
[9844796] CurrentDirectory by Following. [9844796] D: / Winnt / System32
[9844796] Current Module FileName by Following. [9844796] E: / Microsoft / Desktop / Simple_Service_02/##simple_service.exe
[9844796] Re-set the current directory position [9844796] CurrentDirectory by Following. [9844796] E: / Microsoft / Desktop / Simple_Service_02
[9844796] Numargscount = 0x1 (1) [9844796] Command line parameter 0x0 (0) [9844796] E: / Microsoft / Desktop / Simple_Service_02/#simple_Service.exe
[9844796] Success To RegisterServiceCtrlhandler [9844796] Created synchronization object
[9845000] Waiting for the synchronization signal timeout [9845000] SetServiceStatus successfully!
[9845500] Progress = 0x1 (1)
[9846000] Progress = 0x15 (21)
[9846500] Progress = 0x29 (41)
[9847000] Progress = 0x3d (61)
[9847500] Progress = 0x51 (81)
[9848000] Progress = 0x65 (101)
[9848500] Progress = 0x79 (121) [9848500] SetServiceStatus to service_running!
[9849500] Doing Something ...
[9849609] Doing Something ...
[9849703] doing Something ...
[9849812] Doing Something ...
[9849906] Doing Something ...
[9850015] Doing Something ...
[9850062] Go INTO Service_ctrl function.
[9850062] Recive Service_Control_Stop
[9850109] Doing Something ...
[9850218] Doing Something ...
[9850265] The service status has been set to service_stop_pending, and the synchronization object is set to an excitation state. [9850312] Synchronous object is triggered
[9850312] Service_Maincleanup!
[9850312] setServiceStatus to service_stopped success!
[9850765] The service is now stoped [9850765] StartServiceCtrlDispatcher Complete.
[9850765] Record end at date: 2003.08.06 & Time: 16:19:31.
· Basic process introduction:
The first is in the constructor, first obtain the source path and name of the execution file in the command line, generate a corresponding .log file name according to the name (if there is existence to the recycle station). Apply for memory, create a file name (if repeated, append .log retry), set the available tag (Active = true).
Then, in the process of use, use the method of :: Write (), write the information you want to write to the buffer (please less than 512 bytes, otherwise open up a larger buffer, the buffer is full, writing Go to the .log file). After using :: Last () method at the end of the .log file (also forced buffering write hard drive) to add time dates.
Finally in the destructor. Natural is three songs, activiVe = false; closehandle (); and release buffer
To use this class, please include the class file, definition except all functions. as follows:
#include "runtimelog.cpp" runtimelog log;
The following is an example used in the window:
LResult Callback WinProc (HWND HWND, UINT UMSG, WPARAM WPARAM, LPARAM LPARAM) {char string [128] = ""; WSPrintf (String, "WinProc with Umst = 0x% x", UMSG); log.write (string);
····
Finally, please remember to call :: Last () method. Otherwise, if you use EXITPROCESS (); to exit the program, the destructor I defined doesn't work.
The use of this class is roughly the same in the BLAND C Builder, and it is basically available by my test ... and Win98 and Win2K are basically available (unknown in WinXP).
(Disclaimer: This file can be modified, used or reprinted, but I don't have any consequences that use this class):
Not much, the following is the source file of the class: (Full text - March 16, 2003 _am: 11:16)
// ******************************************************** **************************** // ******* FileName: runtimelog.h ******** ****************************** * ****************** *********************************************************** **********
#ifndef __runtimeloginclude # define __runtimeloginclude // include Something Here
// ************************************************* *** # include
PUBLIC:
Runtimelog (); ~ runtimelog (); // Destructor Void Last (Bool Show); void Last (); int showResult (dword delay);
Bool Group, Nobuff, Lastshow; // Used to group information
Private: / / About the Type of Function Pointer Declaration TypeDef Winshellapi Int (WinApi ShellFile);
Bool Active, DOLOG, NOSYSTIME; DWORD OFFSET; // Indicates the memory use offset DWORD BUFFSIZE; DWORD NUMTOWRITE; LPSTR SYSTICK; Handle FileHandle; Char * LPBUFF; // Used to apply for memory char logfile [512];
LPSTR DWNUM2STR (DWORD VAL);
PUBLIC:
DWORD hlstrcpy (LPSTR Str1, LPSTR Str2, DWORD Len); DWORD hlstrcat (LPSTR Str, LPSTR Plus, DWORD StrLen, DWORD PlusLen); LPSTR GetDate (); LPSTR GetTime (); LPSTR GetSysTick (DWORD * len); int write ( LPSTR LPSTR); int NumberWrite (LPSTR LPSTR, DWORD VAL); int WriteLog (Void); Void MSG (LPSTR STR);
} Runtimelog, * pruntimelog; // end of class runtimelog
// at include Last # endif // # iFNDef __runtimeloginclude /// ******************* * **************** *************** ///
// ******************************************************** **************************** // ******* FileName: runtimelog.cpp ******** ****************************** * ****************** * Version: 1.12 ************************************************* / / ********** *********************************************************** ********************* // Disclaimer: the file can be easily modified, used or reproduced, but I do not use any kind of consequences caused by the responsible // author: `海 海 ************ E-mail: free77@163.net********************************** / / * *********************************************************** ************************* / / You can define your classes inside the function, as follows the definition method of using the New. ********************* // runtimelog * RTLOG = new runtimelog; then in the last delete rtlog; ******** // can also be used The following method is defined: Runtimelog log; and it is best to explicitly call destructor ********* // ********************** *********************************************************** *** // The external interface is mainly :: Write (""); used to write information to buffer memory, //, :: Last (); used for the final end portion, write to the .log file. The buffer content / / can also be called directly: WriteLog (); to write buffer content (if any if any) is written to .log file. // Ver 1.02 new information Packet function, use group to control whether the packet // has been corrected automatic write buffer to disk error ..., buffering to 2048
#include
// Constructor :: runtimelog () // without parameter constructor {nobuff = false; lastshow = false; active = false; nosystime = false; group = true;
OFFSET = NULL; NUMTOWRITE = NULL; SYSTICK = NULL; FileHandle = NULL; LPBUFF = NULL; BUFFSIZE = 2048; // Setupize size
Bool delold = false; // Set whether you want to throw away the old log dword overwrite = true; // Set whether you want to overwrite the old log, if it is not lost above words, Word Torecyclebin = false; // Set whether the old log is put Recycle bin
OverWrite = OverWrite CREATE_ALWAYS: CREATE_NEW; // a macro definition ToRecyclebin = ToRecyclebin FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION: FOF_SILENT | FOF_NOCONFIRMATION; // · Application available memory as a buffer space, point lpBuff, size BuffSize??
// lpbuff = (char *) Heapalloc (getProcessHeap (), Heap_zero_memory, buffsize; lpbuff = new char [buffsize]; // lpbuff = buffer;
If (lpbuff! = null) {// · Get the process file name, change into the .log file name, find if it is repeated, is sent to getModuleFileName (null, lpbuff, buffsize); HLSTRCPY (logfile, lpbuff, null ); Getlongpathname (logfile, logfile, 512); // If you call this function in Win98, you may give a short file name format uint len = strlen (logfile); uint i = 0; // then remove the extension from behind FOR (I = LEN; I> 0; I -) {IF (logfile [i] == '.') {HLSTRCAT (Logfile, "Log", I, 4); LEN = LEN 3; BREAK }}
// First determine whether the file is loop: // if you cannot create a file once successfully. IF ((GetFileAttributes (Logfile) == -1) || (GetLastError () == Error_File_not_Found); // MSG ("File does not exist");
Else if (DELOLD) / / The site is set to TRUE to delete the original file
{// Discovery file already exists, you need to thrown into the recycleopstructa fileop; lpshfileopstruct lpfileop = & fileop; Memset (LPFileop, Null, Sizeof (fileop));
Fileop.fflags = Torecyclebin; fileop.wfunc = fo_delete; fileop.pfrom = logfile; lpfileop-> hwnd = null;
// * / / Regarding the file operation of the runtime, define the function of the function's pointer shellfile * lpshfileOperation = null; // Function pointer defines hmodule hlib = loadingLibrary; if (hlib) {lpshfileOperation = Shellfile *) getProcaddress (HLIB, "ShfileOperation"); if (lpshfileOperation) {/ * if (* / lpshfileOperation (lpfileop); // msg ("SHFileOperation is issued during execution");} Else MSG ("shell32. There is no such function in DLL "); if (! freelibrary (hlib)) msg (" release DLL failed ");} else msg (" no shell32.dll "); // * /} // throw garbage completion
/ / · Create a new file, write time FileHandle = Createfile (logfile, generic_write, file_share_read, null, overwrite, file_attribute_normal, null); if (filehandle == invalid_handle_value) {// When you can't create a new file Try to increase the file suffix if (HLSTRCAT (Logfile, ", NULL, 4) <125) goto loop; else {msg (" The problem in the CreateFile execution process, give up the retry. "); / * EXITPROCESS (0 ); * /}} Else {// handle is valid to perform setFilePointer (FileHandle, getFileSize (NULL), NULL, FILE_BEGIN); // Set the original size
Writefile (FileHandle, "[Source Path & FileName:], Strlen (" [Source Path & FileName:]), & NumTowrite, Null; Writefile (FileHandle, Logfile, Strlen (Logfile), & NumTowrite, NULL; / * Used in branch * / writefile (FileHandle, "/ X0D / X0A", Strlen ("/ X0D / X0A"), & NumTowrite, NULL;
WSPrintf (LPBUFF, "Record Start At Date:% S & Time:% s.", getdate (), gettime ());
Systick = getSystick (& NumTowrite); // Get System Time Writefile (FileHandle, Systick, NUMTOWRITE, & NUMTOWRITE, NULL);
Writefile (FileHandle, LPBuff, Strlen (LPBuff), & NumTowrite, NULL
/ * Used in branch * / writefile (FileHandle, "/ X0D / X0A", Strlen ("/ x0d / x0a"), & numTowrite, null; if (! Setndoffile (filehandle)) MessageBox (null, "setting is unsuccessful "," ?? ", MB_ok | MB_TOPMOST); // Write data tail
// CloseHandle; FileHandle = INVALID_HANDLE_VALUE; // Close the handle LPBUFF [0] = null;} // Estimate the execution of the handle is valid; DOLOG = true;} else active = false; Nosystime = false; Write ("");
Return;}
// ******************************************************** ***************** VOID RUNTIMELOG :: Last () {last (0);} void runtimelog :: Last (Bool show) {group = false;
// Write the time IF (Active) {WRITELOG (); if (lpbuff! = Null) {if (filehandle == invalid_handle_value) {msg ("There is a problem in the final WriteLog process"); EXITPROCESS (0) } Else {// handle is active
/ * Used in branch * / writefile (FileHandle, "/ X0D / X0A", Strlen ("/ x0d / x0a"), & numTowrite, null; system = getsystick (& number); // Get system time Writefile (FileHandle, Systick) Numtowrite, & NumTowrite, NULL;
WSPrintf (LPBUFF, "Record End at Date:% s.", getdate (), gettime ()); Writefile (FileHandle, LpBuff, Strlen (LPBuff), & NumTowrite, NULL
/ * Used in branch * / writefile (FileHandle, "/ X0D / X0A", Strlen ("/ X0D / X0A"), & NumTowrite, NULL;
If (! setndoffile (filehandle (filehandle)) MSG ("Set the end is not successful"); // Write the data tail
CloseHandle (FileHandle); FileHandle = Invalid_Handle_Value; // Close Handle LPBUFF [0] = NULL; if (show) showResult (0);} // Perform handle is valid} // end of if (lpbuff! = Null Active = false; // DOLOG = false;} // end of if (active) return;} // ************************************* ************************************************* Runtimelog :: ~ runtimelog () // Destructor {// msg ("Destructure ..."); Last (Lastshow); // MSG ("Prepare Release Memory"); // HeapFree (GetProcessHeap (), NULL, LPBUFF); lpbuff = null DOLOG = FALSE; SLEEP (100); delete lpbuff; lpbuff = null; DOLOG = FALSE;
Return;} // end of ~ runtimelog () // end of constructor and destructor
// ******************************************************** ****************
// Number to the output of the string, the return value is a string pointer // does not have unsuccessful case, nor does it deal with negative weight // The first parameter is the number you want to convert, the second parameter is specified conversion The minimum length // The third parameter is a string, and the first character is used as a placeholder, which can be null, then use the default
LPSTR RUNTIMELOG :: DWNum2Str (dWord Val) {static char Numstr [18] = ""; // _ULTOA (VAL, NUMSTR, 10); WSPRINTF (NUMSTR, "% Lu", VAL); Return Numstr;} / * / LPSTR DWNUM2STR (DWORD VAL, DWORD WIDTH, LPSTR LPSTR) {// The following is a number to ASCII comparison table Static Char Num [11] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48}; static dword base [11] = // The following is to build a base table {0, 1, 10, 1000000, 10000000, 100000000, 1000000000}; static char array [16]; / / Used // array [0] = 0; // truncated strings DWORD INDEX, I, St; Index = 0; ST = 0;
IF (width> 10) width = 10; // width can't be greater than 10
/ / According to the third parameter, change the value of the value of the occupancy (LPSTR & LSTRLEN (LPSTR)) NUM [10] = LPSTR [0]; Else Num [10] = NUM [0];
/ / In order to prevent zero as the divided number IF (VAL == 0) {for (i = width; I> 1; I - /) {Array [index] = NUM [10]; Index ;} array [ Index] = NUM [0]; array [index 1] = 0; return array;} // end of if (val == 0) // Start for normal operation for (i = 10; i> 0; I- -) // This is a loop {IF (! = Base [i]) {st = 1; i ; continue;} else if (! (! (}) / / Ready to fill in placeholders {Array [index] = NUM [10]; index ;}} else {// {array [index] = NUM [VAL / base [i]]; val = val% base [i]; Index ; msg (array);} _ASM {MOV EAX, VAL // This is the divisor MOV EDX, I // Note, the array subscript must be a register Sal EDX, 2 // right shift two or more equal to i * 4 MOV EBX, Base [edx] xor edx, edx // Do you want to empty EDX DIV EBX // before doing the method: Now there is a rest of DX, and the AX is the merchant MOV VAL, EDX / / save the remainder Add Eax, 30H // Adjust to ASCII code MOV ECX, INDEX MOV BYTE PTR Array [ECX], AL // Save the last character result to array add index, 1 // Equivalent to index } // end of _ASM {} } // end of for (dword i = ... array [index] = 0; // final truncation string Return Array;} // * // ************* *********************************************************** **
// ***** Custom function ******************************************* DWORD RUNTIMELOG :: HLSTRCPY (LPSTR STR1, LPSTR STR2, DWORD LEN) {DWORD II = 0; if (len == 0) // If no length is given, the length is automatically calculated (! (Str2 [len] == 0)) LEN } = F (! == STR2) RETURN LEN; IF (STR1 // ******************************************************** ****************** LPSTR RUNTIMELOG :: getdate () {static char Date [15]; date [0] = null; systemtime systemtime; getlocaltime; wsprintf (DATE, "% D.% D.% D", systemtime.wyear, systemtime.wmonth, systemtime.wday; Return Date;} // **************** *********************************************************** LPSTR RunTimeLog :: GetTime () {static char Time [15]; Time [0] = NULL; SYSTEMTIME SystemTime; GetLocalTime (& SystemTime); wsprintf (Time, "% d:% d:% d", SystemTime.wHour, SystemTime . Return Time;} // *********************************************** ******************************* LPSTR RUNTIMELOG :: GetSystick (DWORD * LEN) {// "Royal Breeze" Static char Tick [20] = ""; static dword dwpase = gettickcount (), dwcurtick = gettickcount (); dwpase = dwcurs; dwcurtick = gettickcount (); tick [0] = null; // Clear the original string IF (DWPASTICK! = dwcurtick "&& group) LSTRCAT (Tick," / x0d / x0a "); // If the front and rear time is inconsistent, insert the branch LSTRCAT (Tick," ["); // Pred into the first /// LSTRCAT (Tick, Dwnum2Str (DWCURTICK, NULL, NULL); LSTRCAT (Tick, Dwnum2Str (dwcurtick)); * len = HLSTRCAT (Tick, "]", NULL, 2); // Reputable Return Tick;} / / ************************************************** ****************** INT Runtimelog :: Write (LPSTR LPSTR) // Reserved as a parameter function {DWORD LEN, LENTH, Ticklen; LPSTR TEMP = NULL; LEN = Strlen (LPSTR); if (Len && (! Nosystime) {TEMP = GetSystick (& Number); ticklen = Numtowrite;} else {ticklen = 0;} LENTH = LEN Ticklen 2; if (LENTH> BUFFSIZE) {// msg ("The length is too large, unwinding buffer"); if (FileHandle = Invalid_Handle_Value) {Writefile (FileHandle, NULL); // Write System Time Writefile (FileHandle, LPSTR, LEN, & NUMTOWRITE, NULL); // Write String content / * Used for branch * / Writefile (FileHandle, "/ X0D / X0A", Strlen ("/ X0D / X0A"), & NumTowrite, NULL; setndoffile (FileHandle); Return 1;} return 0; // Len is greater than buffsize and file handle is not available} // end of if (len> buffsize) IF (Offset LENTH)> buffsize) WRITELOG (); If (active) // If it is active, it provides writing {while (! "; DOLOG = FALSE; IF (Ticklen) Offset = HLSTRCAT (LPBUFF, TEMP, OFFSET, TIKLEN); // Write System Time IF (len) Offset = HLSTRCAT (LPBUFF, LPSTR, OFFSET, LEN); // Writing String Offset = HLSTRCAT (LPBUFF, "/ X0D / X0A", Offset, NULL); // Add Branch DOLOG = true; if WRITELOG (); RETURN 1;} RETURN 0;} // ************************************************************ ********************** INT runtimelog :: WriteLog (void) {if (active && offset) {while (! DOLOG); DOLOG = FALSE; IF (FileHandle == INVALID_HANDLE_VALUE) {msg ("Problems in the last written logfile process"); return 0;} Else {// The handle is valid to execute Writefile (FileHandle, LPBuff, Offset, & NumTowrite, NULL); offset = 0; // Remember to set 0 LPBUFF [0] = null; // lpbuff [1] = null; if (! ")) MSG (" Setting the end is not successful ") Data tail } // Perform the handle to perform DOLOG = true; return 1;} else return 0;} // ******************************************** ********************************************************************* VOID RUNTIMELOG :: MSG (LPSTR STR) { MessageBox (NULL, STR, "??", MB_ok | MB_TOPMOST | MB_SETFOREGROUND; RETURN;} // ******************************************************** ***************** INTUNTIMELOG :: NumberWrite (LPSTR LPSTR, DWORD VAL) {char Temp [30]; WSPrintf (Temp, "0x% x (% lu)" , VAL, VAL); Write (LPSTR); if (offset) OFFSET = Offset -2; Else {setndoffile (FileHandle); setFilePointer (FileHandle, GetFileSize (FileHandle, Null);} nosystime = true Write (TEMP); Nosystime = false; return 1L;} // **************************************************** **************************************** INT Runtimelog :: ShowResult (DWORD DELAY) {if (active) {Writelog () WHILE (! DOLOG); DOLOG = FALSE; GetWindowsDirectory (lpBuff, BuffSize); DWORD ExecLen = hlstrcat (lpBuff, "//notepad.exe /" ", NULL, NULL); ExecLen = hlstrcat (lpBuff, logfile, ExecLen, NULL); ExecLen = hlstrcat (lpBuff," / "", NULL, NULL); PROCESS_INFORMATION pi; STARTUPINFO si; memset (& si, 0, sizeof (si)); si.cb = sizeof (si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_MAXIMIZE; // SW_SHOW; CreateProcess (NULL, lpBuff, NULL Null, False, 0, NULL, NULL, & SI, & PI); LPBUFF [0] = NULL; if (delay> 100000) DELAY = 150; if (delay); DOLOG = true; return;} else return;} // ************************************************** ***********