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.

[VC++] Getting special folder path in your program

Special Folders are folders which are presented to the user through an interface as an abstract concept, instead of an absolute folder path. This makes it possible for an application to ask the operating system where an appropriate location for certain kinds of files can be found, regardless of what version or language of operating system is being used.
Some example of special Folders are,My Documents, Desktop Directory, History etc

Inorder to obtain the special folders programmatically use the shell function SHGetSpecialFolderPath(). Below code snippet shows how to obtain the Special folder path of your desktop.

// Allocating string that receives the drive and path
char* szPath = new char[MAX_PATH];
// Getting folder path of Desktop
if( TRUE == SHGetSpecialFolderPath( 0, szPath, CSIDL_DESKTOP, FALSE ))
{
// Successfully retrieved the path in szPath, now you can use
MessageBox( szPath );
}
delete []szPath;

Here[^] is a list of constant special item ID list for getting other special folders, as we used CSIDL_DESKTOP for getting Desktop folder path.


[VC++] Debugging application startup

1. Consider your application is being launched from some other applications and you want to debug the same then how you can do that ?

First of all your module should be made debuggable by building with proper project settings (making release build debuggable). Now start your application, since application is started by some other parent application you cannot get the debug mode.
So what you need to do is that,
a). Take taskmanager->Process tab & Right click the entry corresponding to your process
b). Choose the Debug menu item and press Yes for the warning message shown
c). Visual Studio Debugger will be launched, take File->Open & choose the file which you want to insert break point
d). Insert break point where ever needed and execute it will work fine !

2. Now the question is - How can you debug your application (if lanched by some other process) in the start up, say you want to debug App class constructor or InitInstance() ?
Some of you might have faced the same situation and you would have gone behind putting MessageBox() in some startup function, but there is a better option for the same.
What you need to do for debugging in the startup is
a). Set Auto flag to '1' under registery entry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
b). Add any of the below lines where you want to debug in start up,
_asm int 3;
or
DebugBreak();
Now try start your application, it will automatically launch msdev for debugging and break the execution where you put _asm int 3 or DebugBreak.

[C/C++] #pragma message for compilation errors

You might have faced compilation errors in which you cannot actually find the source from where it is coming. I have faced such situations and in most of the cases same can be solved (or atleast get a clue) on knowing from which file or from which context the error is happening. And here is a preprocessor directive which will help you for finding the cause or source behind your compilation errors.

#pragma message( messagestring )

For example please see the below code with #pragma message and its compilation output(in to VC++ output window).

Code
// Test.cpp : Defines the class behaviors for the application.//
#pragma message ("------------Before include stdafx.h---------")
#include "stdafx.h"
#pragma message ("------------Before include Test.h---------")
#include "Test.h"
#pragma message ("------------Before include MainFrm.h---------")
#include "MainFrm.h"
#pragma message ("------------Before include IpFrame.h---------")
#include "IpFrame.h"
#pragma message ("------------Before include TestDoc.h---------")
#include "TestDoc.h"
#pragma message ("------------Before include TestView.h---------")
#include "TestView.h"
#pragma message ("------------Before include TestView.h---------")

Output window
--------------------Configuration: Test - Win32 Debug--------------------
Compiling...Test.cpp
------------Before include Test.h---------
------------Before include MainFrm.h---------
------------Before include IpFrame.h---------
------------Before include TestDoc.h---------
------------Before include TestView.h---------
------------Before include TestView.h---------

You can use the #pragma else where in your program and your mesage will be displayed in the debug output window. The messagestring parameter of #pragma message () can be a macro that expands to a string literal, and you can concatenate such macros with string literals in any combination. If you use a predefined macro in the message pragma, the macro should return a string, else you will have to convert the output of the macro to a string.

Tuesday, December 23, 2008

[VC++] Debugging Application in the release mode

When you create applications in VC++ using application wizards the default configuration will be debug configuration. So you can debug easily by pressing F5 key and setting break points(F9) where ever in code. Now what about debugging application in Release mode(For making the project release build configuration select Build->SetActiveConfiguration->Win32Release). Some of you might have find that its difficult to debug with release version(if you are new to VC++). That is you cannot put breakpoint when build with Release configuration. Now when tried with F5 key on a release build application what you can see only is a disassembly window or where ever you put break point, that has been disabled.

So below is what you have to do for making the project debuggable in release version

In Project->Settings->C\C++ tab,
- Set Optimizations to Disable(Debug)
- Set Debug info to Program Database


In Project->Settings->Link->Category General set
- Check Debuginfo


See the below snapshots of Project->Settings changes from default.







Now rebuild and try putting the break point again, now its debuggable!

Friday, December 19, 2008

[General]Private Bytes some useful information

Private Bytes:
Microsoft says,
‘Private Bytes is the current size, in bytes, of memory that this process has allocated that cannot be shared with other processes’.
Going deep...
VM Size in ‘TaskManager’ is actually a misnomer of Private bytes (in Perfmon ) and this is one of the counter we will consider if our module is having some memory leak. Hope most of us have a belief that Private Bytes of a process will increase on increasing the code size or if a new DLL is loaded in to that process. I tell you this is not fully correct! We cannot relate the Private Bytes value with the code size increased or size of the DLL Loaded, also there will be no change in Private Bytes even if the DLL is loaded for the first time or if it’s already loaded by some other process. The Private byte is actually related to the increase in data area & the allocation made by our module or through the DLLs loaded by our module.
There are some segments in each EXE or DLL READONLY, EXECUTEREAD, READWRITE, WRITECOPY. Of this READONLY & EXECUTEREAD correspond to the code or instruction set where as the READWRITE & WRITECOPY area corresponds to the data area. An increase in READWRITE & WRITECOPY (normally very less compared to READONLY+EXECUTEREAD ) area will increase the Private Bytes, but an increase in READONLY & EXECUTEREAD will have no reflection in Private Bytes because these area is loaded in to a shared area of the virtual address space. So for e.g. loading a DLL of size 500K (with READWRITE + WRITECOPY area of 20K) will not increase the Private Bytes of the loading process by 500K but only by 20K(READWRITE + WRITECOPY area). Suppose if the DLL is not rebased (rebasing is specifying load address) it will try to load in the default address (may be @ the address 0X10000000) and if that is failed (if some other DLL is loaded in to that address before) then the whole DLL size will be added to the Private Bytes ! So please take care rebasing DLLs with proper address (prefer non conflicting address).
Ohh You might be getting bored up I know, So let me brief through an expression,
Private Bytes = Memory Allocation from our module + Memory Allocation for our module through the loaded DLLs + (READWRITE + WRITECOPY of our module) + (READWRITE + WRITECOPY of all the loaded DLLs) + The whole size of the DLLs loaded which were not rebased and failed loading in the default address(i.e. READONLY+ EXECUTEREAD+ READWRITE + WRITECOPY of those DLLs)
Let me introduce some tools (if you already know please excuse me). With the below tools we will get the details of how and where our Private Byte is spend (a higher level abstract).
Process Explorer:
This tool is available @ SysInternals (
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx) and is helpful to explore the process details. In our scope it help to know whether the DLLs are rebased and loaded in the expected load address.
VaDump:
This is a command line tool which available in windows 2000 Resource kit (
http://download.microsoft.com/download/win2000platform/vadump/1.00.0.1/NT5/EN-US/vadump_setup.exe) and is used to dump the segment details (READONLY, EXECUTEREAD, READWRITE & WRITECOPY) of virtual address space.

Tuesday, December 16, 2008

[VC++] Debugging with the help of AUTOEXP.DAT

Hope you might have debugged some application in VC++ debugger. Have you ever thought of how you are seeing the value of object as tool tip while debugging. For example, while debugging you point to the CString object you can see the value of member variable m_pchData of CString class.


You can give the same support for your custom defined data structures, suppose you have a complex object which holds many items and you want to know the values stored while debugging (sometimes you can expand the variable in watch/Quick watch window but that is difficult for a complex data structure).
In the below debug snapshot, you can see all the values (even other structure’s value) in the structure INFO_EX_t as tool tip while debugging,



For this all you have to do is modify the file MSDEV_INSTAL_DIR\Microsoft Visual Studio\Common\MSDev98\Bin\AUTOEXP.DAT, add an entry for your data structure also. For showing the above variable expansion I have added the below line,

where ‘st’ in the above line is a format specifier for the string to choose UNICODE or ANSI depending on the current setting.
Another usage of AUTOEXP.DAT is you can prevent the stepping to some specific functions (for eg: CString::operator) while debugging with F11. For that what you have to do is add an entry like what I shown below,
[ExecutionControl]
CString::operator==NoStepInto

Just try it you will find it useful some day !

Monday, December 15, 2008

[VC++] Recursive folder deletion by SHFileOperation

If you have a requirment to delete a folder, you may go first and give a try with API RemoveDirectory(). And you may not be happy with the fact that RemoveDirectory() deletes only an empty directory. The RemoveDirectory() marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed. If you want to delete a directory with RemoveDirectory(), you may need to delete the folder contents recursively each level inside the
folder to be deleted. If you come up with such a situation to delete a folder and all its contents don't spend your time with recursive logic, go for shell function SHFileOperation() with which you can Copy, move, rename, or delete a file system object. For Deleting the folder (which is not empty), below function can be used.

// csDeleteFolderPath_i - Path of the folder to be deleted
bool DeleteFolder( const CString& csDeleteFolderPath_i )
{
// Making the directory name double null terminated
int nFolderPathLen = csDeleteFolderPath_i.GetLength();
TCHAR *pszFrom = new TCHAR[nFolderPathLen + 2];
_tcscpy(pszFrom, csDeleteFolderPath_i);
pszFrom[nFolderPathLen] = 0;
pszFrom[++nFolderPathLen] = 0;
SHFILEOPSTRUCT stSHFileOpStruct = {0};

// Delete operation
stSHFileOpStruct.wFunc = FO_DELETE;
// Folder name as double null terminated string
stSHFileOpStruct.pFrom = pszFrom;
// Do not prompt the user
stSHFileOpStruct.fFlags = FOF_NOCONFIRMATIONFOF_SILENT;
// Delete operation can be undo (to recycle bin)
stSHFileOpStruct.fFlags = FOF_ALLOWUNDO;
//Check for any operation is aborted
stSHFileOpStruct.fAnyOperationsAborted = FALSE;
int nFileDeleteOprnRet = SHFileOperation( &stSHFileOpStruct );
delete []pszFrom;
if( 0 != nFileDeleteOprnRet )
{
// Failed deletion
return false;
}
// Deletion was successfull
return true;
}

Please note that you can customize the file operation with a numerous options set to SHFILEOPSTRUCT object which inturn pass to the SHFileOperation().




Thursday, December 11, 2008

[MSWinOS] Files/folders cannot be created/deleted

Have you ever tried creating folders or files with below names ? If no try now itself, its interesting !
CON
PRN
AUX
NUL
COM1
COM2
COM3
COM4
COM5
COM6
COM7
COM8
COM9
LPT1
LPT2
LPT3
If you simply try create/rename the file/folder using windows xp the file name will not change, remains the created or previous name. On the other hand if you try creating the same in Vista following message will be shown.

You can now try creating by DOS commands in the command line but it will still fail.

OK. So what you think will be wrong with OS ?
MSDN says[^] that
Do not use the following reserved device names for the name of a file: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5,
LPT6, LPT7, LPT8, and LPT9.

Actually these are the reserved names of device drivers of Microsoft Windows Operating System. thats why OS not permitting to do such a thing.
But what to do forbidden fruit is always the sweetest, you may be thinking of creating or deleting the same. So good news is that the operating system leaves some loop hole for us. Creating the above files/folders can be done using command prompt (start->run->cmd). Below is the syntax for the same,
mkdir
\\.\fullpathnameof folder to be created

for eg:

mkdir \\.\C:\testfolder\nul

Above command will create the forbidden folder 'nul' in the path C:\TestFolder .

Now try deleting the created folder from windows xp/vista it will fail showing below messages,

In XP,

In Vista, We can use the reverse logic for removing the same. See the following syntax,
rd \\.\fullpathnameof folder to be deleted

for eg:

rd \\.\C:\testfolder\nul

Now you please try to create/delete Windows' forbidden folders !

Wednesday, December 10, 2008

[VC++] Browse dialog for selecting a folder using SHBrowseForFolder()

If you need to select a folder for some purpose of your application, then you can use the shell function SHBrowseForFolder() to display the browser dialog. For getting the folder path of the selected application use shell function SHGetPathFromIDList().
Please see the below code snippet, you can check and use the same if needed.


BROWSEINFO stBrowseInfo = { 0 };
// Below string will be displayed on the browser dialog
stBrowseInfo.lpszTitle = _T( "Select a directory" );
// Displays a dialog box that enables the user to select a folder
LPITEMIDLIST lpItemIdList = SHBrowseForFolder( &stBrowseInfo );
if( lpItemIdList != 0 )
{
TCHAR tcFolderPath[MAX_PATH];

// Converts the item identifier list to the file system path
if( SHGetPathFromIDList( lpItemIdList, tcFolderPath ) )
{
// Use the folder path obtained

MessageBox(tcFolderPath);
}
// Free the allocated memory
IMalloc *pMalloc = 0;
if( SUCCEEDED( SHGetMalloc ( &pMalloc )) )
{
pMalloc->Free( lpItemIdList );
pMalloc->Release ( );
}
} // If folder selected

On executing the above lines you can have a browser dialog like the one show below

Remember that there are numerous options you can set before calling SHBrowseForFolder() by setting values to the in/out parameter of type LPBROWSEINFO that will qualify the appearance and behaviour of the Browse dialog.