VC++ how to create a .log file and add it lines every time a condition is reached?

sg0502
sg0502 used Ask the Experts™
on
Hello
I have Win32 Application for VC++

I need to VC++ create a .log file (the first time the program runs) and add it lines (time when executed and a custom text) every time a condition is reached?

Any ideas??

Regards!!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
I like this Tracer (attached). It create a txt file near the executable. You can modify it as you wish. For example, modify this line:
hFile = ::CreateFileW(szFileName, GENERIC_WRITE | GENERIC_READ,
                  FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);

Now it creates new file for each application launch. Remove CREATE_ALWAYS, if you'd like to collect data.
To use this function, put the attached code into tracer.h file, everywhere you need the tracer, add #include "tracer.h". Call this Tracer function as you call printf:
Tracer(L"Hello, %s", "world!");
'L' - because the function works with the unicode strings.

#ifndef _TRACER_HEADER_
#define _TRACER_HEADER_

#include <stdlib.h>
#include <wchar.h>

inline void __cdecl Tracer(LPCWSTR lpszFormat, ...)
{
	va_list args;
	va_start(args, lpszFormat);

	int nBuf = 0;
	WCHAR szBuffer[1024];
	ZeroMemory(szBuffer, 1024 * sizeof(WCHAR));

	nBuf = _vsnwprintf(szBuffer+nBuf, 1024, lpszFormat, args);
	static HANDLE hFile = INVALID_HANDLE_VALUE;
	if (hFile == INVALID_HANDLE_VALUE) 
	{
		WCHAR szFileName[MAX_PATH];
		ZeroMemory(szFileName, MAX_PATH * sizeof(WCHAR));
		::GetModuleFileName(GetModuleHandle(NULL), szFileName, MAX_PATH);
		int nLength = lstrlen(szFileName);
		while (nLength > 0)
		{
			nLength--;
			if(szFileName[nLength] == TCHAR('.'))
				break;
		}
		szFileName[nLength + 1] = 0;
		wcsncat(szFileName, L"txt", MAX_PATH - 2);
		hFile = ::CreateFileW(szFileName, GENERIC_WRITE | GENERIC_READ,
			FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
		if (hFile != INVALID_HANDLE_VALUE) 
		{
			DWORD nErr = GetLastError();
			DWORD nWritten = 0;

			SetFilePointer(hFile, 0, 0, FILE_END);

			if (nErr != ERROR_ALREADY_EXISTS)
			{
				char szHeader[2] = { (char)0xFF, (char)0xFE };
				::WriteFile(hFile, szHeader, 2, &nWritten, NULL);
			}

			::WriteFile(hFile, L" ", 1 * sizeof(WCHAR), &nWritten, NULL);
			WCHAR sz[2] = { WCHAR(13), WCHAR(10) };
			::WriteFile(hFile, sz, 4, &nWritten, NULL);
		}
	}

	if (hFile != INVALID_HANDLE_VALUE) 
	{
		DWORD nLength = wcslen(szBuffer) * sizeof(WCHAR);
		DWORD nWritten = 0;
		::WriteFile(hFile, szBuffer, nLength, &nWritten, NULL);
		WCHAR sz[2] = { WCHAR(13), WCHAR(10) };
		::WriteFile(hFile, sz, 4, &nWritten, NULL);
		FlushFileBuffers(hFile);
	}

#ifndef _WIN32_WCE

	::OutputDebugStringW(szBuffer);
	::OutputDebugStringW(L"\r\n");

#endif

	va_end(args);
}


#endif

Open in new window

Commented:
If you need to read something about it:
Logging In C++
http://www.drdobbs.com/cpp/201804215
This is an interesting article that contains an example with explanations.

Here is an "official standard", an open source library:
http://log4cpp.sourceforge.net/

Take a look if you need something really serious:
http://torjo.com/log2/doc/html/index.html
This is boost-log. You can download it from here:
http://tinyurl.com/cm9lum



Author

Commented:
Hello,
I got this error:

C:\Ambientes_2\Operadores.cpp(20) : fatal error C1083: Cannot open include file: 'tracer.h': No such file or directory

Thanks

Commented:
You needed to create this file - take the code I posted and save it in tracer.h file. Put this file in the project folder - somewhere where the compiler will find it for #include.

Author

Commented:
Thnks

Now its included and i got this error:

Compiling...
Operadores.cpp
c:\program files\microsoft visual studio\vc98\include\tracer.h(22) : error C2664: 'GetModuleFileNameA' : cannot convert parameter 2 from 'unsigned short [260]' to 'char *'
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
c:\program files\microsoft visual studio\vc98\include\tracer.h(23) : error C2664: 'lstrlenA' : cannot convert parameter 1 from 'unsigned short [260]' to 'const char *'
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
C:\INVENSYS\Foxboro\C++ Projects\Cambio automatico de ambientes\Ambientes_2\Operadores.cpp(27) : warning C4007: 'WinMain' : must be '__stdcall'
Error executing cl.exe.

Operadores.obj - 2 error(s), 1 warning(s)

Thanks for the help

Commented:
Did you change something?
If not, fix this line:
::GetModuleFileName(GetModuleHandle(NULL), szFileName, MAX_PATH);
should be:
::GetModuleFileNameW(GetModuleHandle(NULL), szFileName, MAX_PATH);

Commented:
and this line:
int nLength = lstrlen(szFileName);
should be:
int nLength = wcslen(szFileName);

Sorry, I used only Unicode projects when wrote this function and never tested it in a project that supports MultiByte Character Set. If it is not a cross-platform application, it does not make any sense to work on Windows with MultiByte.
Commented:
Fixed version
#ifndef _TRACER_HEADER_  
#define _TRACER_HEADER_  

#include <stdlib.h>  
#include <wchar.h>  

inline void __cdecl Tracer(LPCWSTR lpszFormat, ...)  
{  
	va_list args;  
	va_start(args, lpszFormat);  

	int nBuf = 0;  
	WCHAR szBuffer[1024];  
	ZeroMemory(szBuffer, 1024 * sizeof(WCHAR));  

	nBuf = _vsnwprintf(szBuffer+nBuf, 1024, lpszFormat, args);  
	static HANDLE hFile = INVALID_HANDLE_VALUE;  
	if (hFile == INVALID_HANDLE_VALUE)   
	{  
		WCHAR szFileName[MAX_PATH];  
		ZeroMemory(szFileName, MAX_PATH * sizeof(WCHAR));  
		::GetModuleFileNameW(GetModuleHandle(NULL), szFileName, MAX_PATH);  
		int nLength = wcslen(szFileName);  
		while (nLength > 0)  
		{  
			nLength--;  
			if(szFileName[nLength] == TCHAR('.'))  
				break;  
		}  
		szFileName[nLength + 1] = 0;  
		wcsncat(szFileName, L"txt", MAX_PATH - 2);  
		hFile = ::CreateFileW(szFileName, GENERIC_WRITE | GENERIC_READ,  
			FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);  
		if (hFile != INVALID_HANDLE_VALUE)   
		{  
			DWORD nErr = GetLastError();  
			DWORD nWritten = 0;  

			SetFilePointer(hFile, 0, 0, FILE_END);  

			if (nErr != ERROR_ALREADY_EXISTS)  
			{  
				char szHeader[2] = { (char)0xFF, (char)0xFE };  
				::WriteFile(hFile, szHeader, 2, &nWritten, NULL);  
			}  

			::WriteFile(hFile, L" ", 1 * sizeof(WCHAR), &nWritten, NULL);  
			WCHAR sz[2] = { WCHAR(13), WCHAR(10) };  
			::WriteFile(hFile, sz, 4, &nWritten, NULL);  
		}  
	}  

	if (hFile != INVALID_HANDLE_VALUE)   
	{  
		DWORD nLength = wcslen(szBuffer) * sizeof(WCHAR);  
		DWORD nWritten = 0;  
		::WriteFile(hFile, szBuffer, nLength, &nWritten, NULL);  
		WCHAR sz[2] = { WCHAR(13), WCHAR(10) };  
		::WriteFile(hFile, sz, 4, &nWritten, NULL);  
		FlushFileBuffers(hFile);  
	}  

#ifndef _WIN32_WCE  

	::OutputDebugStringW(szBuffer);  
	::OutputDebugStringW(L"\r\n");  

#endif  

	va_end(args);  
}  


#endif

Open in new window

Author

Commented:
Thanks,
there is no error!

however it doesnt create the file
Its supposed to be created in the .exe folder, isnt it?
Whats the name of the txt?

Commented:
The txt-file is near the executable. It is created only if you call Tracer function. At least once.
Tracer(L"Number=%d", 1);

Author

Commented:
Thanks, it works now

How can i make it to print the time stamp when executed?

Author

Commented:
one more thing.
When open, it shows

Hello, ¿¿¿
Hello, ¿¿¿
Hello, ¿¿¿
Hello, ¿¿¿
Hello, ¿¿¿

Commented:
How you use it?
Probably in this case it should be:
Tracer(L"Hello, %s!", L"world");

Pay attention - I use L before the strings. It is Unicode.
I think you will need to work with numbers, like:
int num = 4;
Tracer(L"Number of items is %d", num);

BTW, if you have an MFC application, you can use TRACE in the same way. You will see all messages in the output window in Visual Studio. You can use OutputDebugString and WinDbg for a release version.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial