MFC
How to set timer in mfc dialog?
4![]()
Timers are running everywhere! The moment when your machine starts, when your machine is turned off, in your heart, in your lungs, in your brain and even in your mind, its everywhere. Well, Software application are not exception to timers. We have to use timers in several situations.

But how to create timers and use it?
![]()
For creating timers you can use the api – SetTimer(). In SetTimer() you’ve to specify the time interval in milliseconds, a timer id as UINT, then TimerProc. For each tick of specified timer, windows will call the TimerProc. If you didn’t specify any TimerProc, then a WM_TIMER message will be posted to your window.
You can utilize the Timer ID to set multiple timers using the same TimeProc. You can use KillTimer() to remove the timer. Have a look at the code snippet. In the given code snippet, timer is handled by WM_TIMER message.
// Message Map
BEGIN_MESSAGE_MAP(CDlgDlg, CDialog)
...
ON_WM_TIMER()
END_MESSAGE_MAP()
...
// Timer ID constants.
const UINT ID_TIMER_MINUTE = 0x1001;
const UINT ID_TIMER_SECONDS = 0x1000;
// Start the timers.
void CDlgDlg::StartTimer()
{
// Set timer for Minutes.
SetTimer( ID_TIMER_MINUTE, 60 * 1000, 0 );
// Set timer for Seconds.
SetTimer( ID_TIMER_SECONDS, 1000, 0 );
}
// Stop the timers.
void CDlgDlg::StopTimer()
{
// Stop both timers.
KillTimer( ID_TIMER_MINUTE );
KillTimer( ID_TIMER_SECONDS );
}
// Timer Handler.
void CDlgDlg::OnTimer( UINT nIDEvent )
{
// Per minute timer ticked.
if( nIDEvent == ID_TIMER_MINUTE )
{
// Do your minute based tasks here.
}
// Per minute timer ticked.
if( nIDEvent == ID_TIMER_SECONDS )
{
// Do your seconds based tasks here.
}
}
![]()
“Today is the tomorrow you worried about yesterday” – So enjoy your day!
![]()
Targeted Audience – Beginners.
How to iterate all MFC objects allocated on heap?
0![]()
MFC is famous for memory leaks. Usually we add icing and cherrys to those leaks by adding our own leaks. Is there any mechanism to track those?
Well, if you’re object is a mfc object, which is derived from CObject, then MFC provides an iteration mechanism to iterate through your objects. You can use it to track the count of your objects in heap, you can dump selective objects… etc… etc… Well, how can you do it?
![]()
Use the api – AfxDoForAllObjects(). While calling we’ve to pass a function pointer of expected syntax, and for each CObject derived object in heap, the function will be called. See the sample to iterate all CDynLinkLibrary objects and to find its count.
// This function will be called as callback
// from AfxDoForAllObjects.
void DoForAllObjects(CObject* pObject, void* pContext)
{
// Here context is the pointer to count variable.
int* pCount = (int*) pContext;
// Check whether the object is of type CDynLinkLibrary
if( dynamic_cast<CDynLinkLibrary*>( pObject))
{
// Increment count.
++(*pCount);
}
}
// Iterate objects.
void CDialogDlg::Iterate()
{
// Iterate all CObject instances and get the
// count of instances of CDynLinkLibrary objects.
int DynLinkLibCount = 0;
AfxDoForAllObjects( DoForAllObjects, &DynLinkLibCount );
}
![]()
You can utilize this for finding memory leaks, to find the count of instances of a particular class, you can dump objects of particular class, etc…
Well, one thing to remember – its only available in debug build. So take care!
![]()
Targeted Audience – Intermediate.
How to hook memory allocations?
0![]()
Memory allocation hooking is always handy. For instance, if you want to know whether the memory leak is due to the 3ed party dll calls, then hook the memory allocation and then call the 3ed party api. If the dll does some memory allocation, then your hook function will be triggered. So far so nice – But how to hook the memory allocations?
![]()
You can use the function – AfxSetAllocHook(). See the code snippet below.
// The hook function.
BOOL AFXAPI AllocHook( size_t nSize,
BOOL bObject,
LONG lRequestNumber )
{
// bObject will be TRUE if the allocation
// is a CObject derived class.
return TRUE;
}
void SetHook()
{
// Set the hook.
AfxSetAllocHook( AllocHook );
// Try some allocations.
CDialog* pString = new CDialog;
int* integer = new int;
}
The bObject flag will be true if the allocation is for a CObject derived class.
![]()
AfxSetAllocHook() is only available in debug version. So take care!
![]()
Targeted Audience – Intermediate.
How to dump the call stack?
0![]()
While debugging you can see the call stack at any time you wish by pressing Alt+7. But what to see the callstack when your executable is running without a debugger?
![]()
You can dump the call stack by calling – AfxDumpStack(). By default the output will be send by TRACE macro in debug build and if its release build, the output will be copied to the clipboard. You can specify the target destination to where the call stack information is to be copied. See the sample code snippet below.
// Dump the call stack.
AfxDumpStack( AFX_STACK_DUMP_TARGET_BOTH |
AFX_STACK_DUMP_TARGET_ODS );
See the sample call stack dump[Taken from MSDN].
=== begin AfxDumpStack output === 00427D55: DUMP2\DEBUG\DUMP2.EXE! void AfxDumpStack(unsigned long) + 181 bytes 0040160B: DUMP2\DEBUG\DUMP2.EXE! void CDump2Dlg::OnClipboard(void) + 14 bytes BFF73663: WINDOWS\SYSTEM\KERNEL32.DLL! ThunkConnect32 + 2148 bytes BFF928E0: WINDOWS\SYSTEM\KERNEL32.DLL! UTUnRegister + 2492 bytes === end AfxDumpStack() output ===
You might notice that Its not same as the Call stack that we see in Debugger. The syntax for each entry is as follows.
[Address]: [Module FileName ] [FunctionName] + [Offset] BFF73663: WINDOWS\SYSTEM\KERNEL32.DLL! ThunkConnect32 + 2148 bytes
![]()
You can use the DebugView application to get the call stack when the executable is running standalone. Download it from http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx.
![]()
Targeted Audience – Intermediate.
CMirrorFile – An undocumented MFC tale.
0![]()
Did you ever heard about CMirrorFile? The possibility is less, Because its an undocumented MFC class. It’s also used for file operations. We can write, delete do anything to a file by using CMirrorFile. But if you wish you can rollback the changes at any point before committing. Seems interesting?
![]()
In CMirrorFile, you can open a file like CFile and you can do as may operations. All the changes will be committed only if you call CMirrorFile::Close(). If you want to rollback the changes, then call CMirrorFile::Abort(). See the code snippet. Its self explanatory.
#include "afxpriv.h"
...
CMirrorFile MirrorFile;
MirrorFile.Open( _T("C:\\Database.txt"),
CFile::modeCreate | CFile::modeReadWrite );
// Do as many operations as you want.
// Truncate current file.
MirrorFile.SetLength( 0 );
// Write the file content.
CString FileContent = _T("File modified by using CMirrorFile.");
MirrorFile.Write( (LPCTSTR)FileContent, FileContent.GetLength());
// Decide whether to abort or not.
bool bAbort = false;
if( bAbort )
{
// Abort the changes.
// The source file will be the same.
MirrorFile.Abort();
}
else
{
// Close and commit the changes.
MirrorFile.Close();
}
![]()
Actually when we open a file using CMirrorFile, Its really creating a temporary file. All the further changes that you apply is updated to the temporary file copy. When you call Close(), CMirrorFile, updates the temporary file copy, then replaces the master file with temporary file by using api – ReplaceFile(). When you call Abort(), CMirrorFile just deletes that temporary copy of file.
Cool! You can use CMirrorFile, if you want to do several operations without damaging the main file and can commit only if you need or else you are free to rollback at any point.
![]()
Targeted Audience – Intermediate.
How to enable tooltip for your dialog controls?
5![]()
Have a number of controls in your dialog. May be a single line of tooltip will add beauty to it. So how can you add tooltips for the controls in your dialog? Its easy. Just follow the steps.
![]()
Basically you’ve to enable tooltips by calling EnableToolTips() and then handle the TTN_NEEDTEXT message in your dialog. When its time to show a tooltip, windows will send you the TTN_NEEDTEXT message with control’ handle and you’ve to specify the tooltip text to be shown. From handle you can get Dialog control ID. Once you have the control ID, you can specify which tooltip have to be shown for that control. See it step by step. I assume you use MFC. Eventhough you follow the tradition style, just go through the steps, you can easily grasp it.
1) Call EnableToolTips() in yout dialog initialize function. The best place is in dialog initialization routine – CDialog::OnInitDialog().
2) Now add message handler for TTN_NEEDTEXT in messagemap. The following codesnippet enables tooltip notification for all controls in your dialog.
BEGIN_MESSAGE_MAP(CDialogDlg, CDialog)
...
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, OnToolTipNotify)
END_MESSAGE_MAP()
3) Now declare the tooltip handler in your header as follows.
afx_msg BOOL OnToolTipNotify( UINT id,
NMHDR* pNMHDR,
LRESULT* pResult );
4) Now define the tooltip handler in your cpp file as follows
BOOL CDialogDlg::OnToolTipNotify( UINT id,
NMHDR * pNMHDR,
LRESULT * pResult )
{
// Get the tooltip structure.
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
// Actually the idFrom holds Control's handle.
UINT CtrlHandle = pNMHDR->idFrom;
// Check once again that the idFrom holds handle itself.
if (pTTT->uFlags & TTF_IDISHWND)
{
// Get the control's ID.
UINT nID = ::GetDlgCtrlID( HWND( CtrlHandle ));
// Now you have the ID. depends on control,
// set your tooltip message.
switch( nID )
{
case IDC_BUTTON1:
// Set the tooltip text.
pTTT->lpszText = _T("First Button");
break;
case IDC_BUTTON2:
// Set the tooltip text.
pTTT->lpszText = _T("Second Button");
break;
default:
// Set the tooltip text.
pTTT->lpszText = _T("Tooltips everywhere!!!");
break;
}
return TRUE;
}
// Not handled.
return FALSE;
}
![]()
Targeted Audience – Beginners.
How to set the Minimum and Maximum window size while Resizing?
2![]()
In several applications, you might already seen, the dialog won’t resize after a particular limit. In other words those dialogs have a minimum and maximum dialog size even though they supports resizing. So how can we set the minimum – minimum size and maximum – maximum size of a dialog?
![]()
You can utilize the message – WM_GETMINMAXINFO. This message is sent to the dialog to get the minimum and maximum window size. Pointer to struct MINMAXINFO is send as message params. We’ve set our required minimum and maximum window sizes in this MINMAXINFO struct. See the code snippet below. For easiness, I’ve implemented it in MFC.
Modify the message map as follows
BEGIN_MESSAGE_MAP(CDialogDlg, CDialog)
...
ON_WM_GETMINMAXINFO()
END_MESSAGE_MAP()
Now add a function with the following signature to your dialog class.
void CDialogDlg::OnGetMinMaxInfo( MINMAXINFO FAR* pMinMaxInfo )
{
// Preferred Maximum X & Y.
const int MAX_SIZE_X = 750;
const int MAX_SIZE_Y = 650;
// Preferred Minimum X & Y.
const int MIN_SIZE_X = 400;
const int MIN_SIZE_Y = 350;
// Set the maximum size. Used while maximizing.
pMinMaxInfo->ptMaxSize.x = MAX_SIZE_X;
pMinMaxInfo->ptMaxSize.y = MAX_SIZE_Y;
// Set the Minimum Track Size. Used while resizing.
pMinMaxInfo->ptMinTrackSize.x = MIN_SIZE_X;
pMinMaxInfo->ptMinTrackSize.y = MIN_SIZE_Y;
// Set the Maximum Track Size. Used while resizing.
pMinMaxInfo->ptMaxTrackSize.x = MAX_SIZE_X;
pMinMaxInfo->ptMaxTrackSize.y = MAX_SIZE_Y;
}
Now try to resize your dialog. Wowwww!!!
![]()
You can just handle it in the classic message proc also. All you should know is about the struct MINMAXINFO and its members.
![]()
Targeted Audience – Beginners.
How to update bulk amount of data to GUI controls without flicker.
0![]()
Usually for Listbox and Tree control, may be you need to add and delete thousands of entries. While doing so, its obvious that the control will flicker. It might be annoying to the user. So how can you avoid it?
![]()
You can use the api – LockWindowUpdate() and UnlockWindowUpdate() for remove the flicker while updating the UI. If a window is locked by calling LockWindowUpdate(), the the further call for getting the device context will return one with empty visible region. When you call UnlockWindowUpdate(), system invalidates the area and will send WM_PAINT. The WM_PAINT will be send only if some drawing is done to the window after locking.
You can download sample from here, which shows the difference.
See sample code snippet below.
// Lock the EditBox.
m_EditBox.LockWindowUpdate();
// Add any number of strings to it.
for( DWORD Index = 0; Index < 5000; ++Index )
{
CString csMessage;
csMessage.Format( _T("Item %d"), Index );
m_EditBox.AddString( csMessage );
}
// After updating, unlock it.
m_EditBox.UnlockWindowUpdate();
![]()
Please note that, only one window can be locked at a time.
![]()
Targeted Audience – Beginners.
How to enable Auto Completion for Editboxes?
0![]()
In windows, we experience auto completion in several places such as URL auto completion in Internet Explorer address bar, File path auto completion in Run dialog etc. You can enable auto completion in editboxes or comboboxes of your application too.
![]()
Use the shell function – SHAutoComplete() to enable the auto completion feature for any edit boxes. Please see the following code snippet for how to use it.
#include "objbase.h" #include "Shlwapi.h" ... // Initialize COM. ::CoInitialize(0); // Get the window handle. // For time being, i took it from a ctrl variable. HWND hEditWnd = m_EditCtrl.GetSafeHwnd(); // Enable Auto completion. ::SHAutoComplete( hEditWnd, SHACF_DEFAULT );
![]()
Both File path and URL auto completion will be enabled by default. If you want any one of these, just use – SHACF_FILESYSTEM or SHACF_URLALL appropriately. Have a look at MSDN for other useful flags.
Don’t forget to add library – Shlwapi.lib to your project settings.
![]()
Targeted Audience – Beginners.
WM_COPYDATA can be used as simple IPC mechanism.
3![]()
Sending and receiving data between processes are one of the greatest headaches that we face. For that many mechanisms are there – such as COM, Sockets, but a bit complicated… There is comparatively simple mechanism for doing the same. i.e. WM_COPYDATA window message.
![]()
For IPC communication between two processes, you just need a hidden window created in each and by using the window handle in target process you can send data to it. For sending data via WM_COPYDATA, the following are requirements.
WPARAM – Handle of window in target process.
LPARAM – Pointer to COPYDATASTRUCT which contains data to be exported.
Please see the following code block about how to use it.
void CMyDialog::SendData( HWND hTargetWindow_i,
void* pData_i,
DWORD dwSize_i )
{
// structure holding data information.
COPYDATASTRUCT stCopyData = { 0 };
stCopyData.lpData = pData_i;
stCopyData.dwData = dwSize_i;
// Send the data.
SendMessage( WM_COPYDATA,
(UINT) hTargetWindow_i,
(ULONG) &stCopyData );
}
In the receiving Window, if you are using MFC, you need to handle the WM_COPYDATA message by adding message handle using ON_WM_COPYDATA() and handler function with proto -
afx_msg BOOL OnCopyData( CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct );
![]()
Targeted Audience _ intermediate.
Recent Comments