Tuesday, December 30, 2008
[VC++] Reading and Writing INI files
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 \
#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
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
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
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
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
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
#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
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
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.
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,
[ExecutionControl]
CString::operator==NoStepInto
Monday, December 15, 2008
[VC++] Recursive folder deletion by SHFileOperation
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
CON
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:
Now you please try to create/delete Windows' forbidden folders !
Wednesday, December 10, 2008
[VC++] Browse dialog for selecting a folder using SHBrowseForFolder()
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 );
}
} // If folder selected
On executing the above lines you can have a browser dialog like the one show below