Tuesday, December 30, 2008

[VC++] Reading and Writing INI files

INI files are simple text files with a basic structure. The name "INI file" comes from the file name extension usually used, ".INI", that stands for "initialization". Sometimes, files using the INI file format will use a different extension, such as ".CFG", ".conf", or ".TXT".
INI files contain one or more sections. Each section begins with a section name, which is followed by zero or more entries. An entry associates a keyname with a value. The general format is:
[section]
keyname=value

So in Your application if you might be in need for saving some configuration and using it then you can prefer .INI files. Here is the code which shall explain how to read and write INI files,

Writing Section Data
Code
// Writing section with one key
if(::WritePrivateProfileSection("Section1", "key1=Value1\0", "C:\\Test.ini"))
{
// Success
}
// Writing section with more than one key
if(::WritePrivateProfileSection("Section2", "key1=Value1\0key2=Value2\0", "C:\\Test.ini"))
{
// Success
}
C:\Test.ini on executing above code
[Section1]
key1=Value1
[Section2]
key1=Value1
key2=Value2

Writing Key & value
Code
// Modify the string value of a given key
if( ::WritePrivateProfileString("Section1", "key1", "NewValue1", "C:\\Test.ini"))
{
// Success
}
// Write new key and string value
if( ::WritePrivateProfileString("Section1", "key2", "Value2", "C:\\Test.ini"))
{
// Success
}
C:\Test.ini on executing above code
[Section1]
key1=NewValue1
key2=Value2
[Section2]
key1=Value1
key2=Value2

Remove Key
Code
// Remove the key by writing null value
if( ::WritePrivateProfileString("Section2", "key2", 0, "C:\\Test.ini"))
{
// Success
}
C:\Test.ini on executing above code
[Section1]
key1=NewValue1
key2=Value2
[Section2]
key1=Value1

Write Number
Code
CString csNum;
csNum.Format( "%d", 1000 );
// Write new key with number value
if( ::WritePrivateProfileString("Section1", "key3", csNum, "C:\\Test.ini"))
{
// Success
}
C:\Test.ini on executing above code
[Section1]
key1=NewValue1
key2=Value2
key3=1000
[Section2]
key1=Value1

Read String
Code
char *szValue = new char[MAX_PATH];
memset( szValue, 0, MAX_PATH );
// Read string from the INI file
if(::GetPrivateProfileString( "Section1", "Key1", 0, szValue, MAX_PATH, "C:\\Test.ini" ))
{
MessageBox( szValue );
}
Output
MessageBox will be shown with 'NewValue1'

Read Number
Code
// Read number from the INI file
int nNum = ::GetPrivateProfileInt("Section1", "Key3", 0, "C:\\Test.ini");
CString csNum;csNum.Format( "%d", nNum );
MessageBox( csNum );
Output
MessageBox will be shown with '1000'

Monday, December 29, 2008

[C/C++] Using continuation character \

You can use the backslash (\) as a continuation character. When a newline character (equivalent to pressing the RETURN key) immediately follows the backslash, the compiler ignores the backslash and the newline character and treats the next line as part of the previous line. This is useful primarily for preprocessor definitions longer than a single line. For example:
#define assert( exp ) \

((exp) ? (void) 0:_assert( #exp, __FILE__, __LINE__ ))


Above example may be ok but consider if it is a string which was separated by \ in two lines what will be the result ?
See the below example. Consider replacing /*Use empty space*/ with a set of empty spaces of that length.

Code:
OutputDebugString( "This is a very long \
/*Use empty space*/string." );

Output:
This is a very long /*Use empty space*/string.

See the gap in between "long string" its nothing but the space in the second line's begining to "string". We have compromised the output beauty for the code beauty. If you have used the code as shown below then output will look fine but about the code beauty, code alignment & code readability.

OutputDebugString( "This is a very long \
string." );


Output:

This is a very long string.

But I know what you will be looking for is both the code beauty (alignment) with expected output. Then here is the optimal solution for using strings split in to two lines. Close double quotes (") when the line ends and keep the string in next line inside the double quotes.

Code:
OutputDebugString( "This is a very long "
/*Use empty space*/"string." );

Output:
This is a very long string.


[VC++] Writing event log to Event Viewer

You might have viewed the event logs (Start->Run->eventvwr), but have you ever tried writing the logs to the event viewer ? If you are interested to do the same, then following are the APIs which will help you,
RegisterEventSource() // For registering event source
ReportEvent() // For writing event log
DeregisterEventSource() // Release the event log handle

Below code snippet will write application event log to event viewer and will give you a better idea.
// Register event source.
HANDLE hEventLog = RegisterEventSource( 0,"Test Evt Logger");
// No CategoryWORD
wCategoryID = 0;
// Event ID in the message file associated with the event source
DWORD dwEventID = 1000;
// No security attributes set
PSID pSecurity = 0;
// No of strings to be logged
WORD wNumofStrs = 2;
// No raw data so size is 0
DWORD dwDataSize = 0;
// No raw data
LPVOID* lpRawData = 0;
// Strings to be logged to event viewer
LPCTSTR LogStrings[] = { "First string to event viewer", "Second string to event viewer" };
// Logging string to event viewer with type information
if( !ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, wCategoryID, dwEventID, pSecurity, wNumofStrs, dwDataSize, LogStrings, lpRawData ))
{
// Failed reporting event
}
// Closes the handle to the specified event log
DeregisterEventSource( hEventLog );

Below snapshot shows the output of the above code,

[VC++] OutputDebugString for error/infomation tracing

Have you thought of how to make your application informing the error/information with out annoying the user (say through MessageBox()). For example to get the performance of a particular operation or if some irrelevant error/information which can be ignored from the user is to be logged/traced then we could not prefer MessageBox or so. In such a context OutputDebugString() is an API of interest.It sends a string to the debugger for display. If the application has no debugger, the system debugger displays the string. If the application has no debugger and the system debugger is not active, OutputDebugString() does nothing. Also note that applications should send very minimal debug output and provide a way for the user to enable or disable its use. Below example gives a way to get the performance of an operation and trace the performance obtained.

Code

CString csMsg;DWORD dwTime = GetTickCount();
// Do some operations here for demo Sleep() is used
Sleep(1000);
dwTime = GetTickCount() - dwTime;
csMsg.Format(" #PERF# Time consumed for the operation is %d ms", dwTime);
OutputDebugString( csMsg );

Output

#PERF# Time consumed for the operation is 1002 ms

The output can be obtained in the DebugView or will be available in the Visual Studio debugger output window (only while debugging). DebugView is an application that let you monitor debug output on your local system, or any computer on the network that you can reach via TCP/IP. There are numerous features available with Debugview, one example is filtering the debug view output. If you want only one type of output then you can filter specifying the string. For example specifying #PERF# in Edit->Filter/Highlight->Include and execute then you can find only strings with #PERF# logged in to the DebugView. Just check and find out the numerous options available with DebugView.

Wednesday, December 24, 2008

[VC++] Using ShellExecute for starting applications

You might have thought of starting an application programatically, for example starting MS word or starting a browser with an intented page programmatically. Let me introduce you an API ShellExecute() and its usage through some examples. ShellExecute() Performs a specified operation on a specified file.This method allows you to execute any commands in a folder's shortcut menu or stored in the registry. Below examples will give you a better idea,

1. Start freshtechies.blogspot page in your default browser .
ShellExecute( 0, "open", "http://freshtechies.blogspot.com", 0, 0, SW_SHOWNORMAL);

2. Open the folder in C:\Windows
ShellExecute( 0, "open", "c:\\Windows", 0, 0, SW_SHOWNORMAL);

3. Launch the Shell's Find utility for C:\Windows
ShellExecute( 0, "find", "C:\\Windows", 0, 0, 0);

4. Start MS Word
CString csWordPath = "C:\\Program Files\\Microsoft Office\\Office12\\winword.exe";
ShellExecute( 0, "open", csWordPath, 0, 0, SW_SHOWNORMAL);

Now you are in a position to use ShellExecute(), let me call your attention to an extended version of this function ShellExecuteEx() is available with which you can set many options for controlling the operation to be performed.