VC++ Tips
VC++ Tips
VC++ Tips
How do I extract programmatically, the path of the directory where the program
currently running is situated?
Ans: Use GetModuleFileName( ) function. In Windows an '.EXE' or '.DLL' is called module.
The GetModuleFileName( ) function takes three parameters, a handle to the module
which in case of an '.EXE' would be NULL. The second and third parameters specify the
address of buffer that stores the path and the size of the buffer respectively. Following code
snippet demonstrates the use of this function.
void CGetmodnameDlg :: OnGetname( )
{
char buffer[MAX_PATH] ;
if ( GetModuleFileName ( NULL, buffer, MAX_PATH ) != 0 )
* ( strrchr ( buffer, '\\' ) + 1 ) = '\0' ;
MessageBox ( buffer ) ;
}
Here, we have called strrchr( ) function to eliminate the filename from the full path.
MessageBox ( str ) ;
We have used an API function SystemParametersInfo( ) that would fill the nc structure
with the corresponding information. The parameter SPI_GETNONCLIENTMETRICS specifies
the system parameter about which we want to get the information.
How do I turn off the tool bar and status bar programmatically?
Ans: Write following code in a member function of CMainFrame class, and call this function
through a handler or any other function when you want to turn off toolbar and status bar.
void CMainFrame::fun( )
{
if ( m_wndToolBar.IsWindowVisible( ) )
SendMessage ( WM_COMMAND, AFX_IDW_TOOLBAR, 0L ) ;
if ( m_wndStatusBar.IsWindowVisible( ) )
SendMessage ( WM_COMMAND, AFX_IDW_STATUS_BAR, 0L ) ;
}
How do I write code, so that if connection fails, then using same socket object
connection for other server should get established?
Ans: This is shown in following code fragement.
void CClientDlg :: OnConnect( )
{
UpdateData ( TRUE ) ;
m_commsocket.Create( ) ;
BOOL result = m_commsocket.Connect( "User17", 100 ) ;
if ( !result )
{
MessageBox ( "Server not found! Try again..." ) ;
m_commsocket.Close( ) ;
m_commsocket.Connect( "User100", 100 ) ;
}
}
Here, m_commsocket is an object of class (derived from CSocket) that handles socket
related operations like, accept request, receive messages, etc. The values User17 or
User100 are the machine names on which the server application is supposed to be running.
Calling Close( ) closes the socket. As a result, same socket object can be reused to
establish connection with the server.
How do I remove the window caption 'Untitled' that gets added to the window of
an SDI application created with Doc/View support?
Ans: Write following statement to the PreCreateWindow( ) function of the CMainFrame
class.
BOOL CMainFrame :: PreCreateWindow ( CREATESTRUCT& cs )
{
cs.style &= ~FWS_ADDTOTITLE ;
//AppWizard generated code
}
Here, we have removed FWS_ADDTOTITLE style from the window. FWS_ADDTOTITLE is an
MFC-specific style that instructs the framework to add the document title to the windows
caption.
than at some later time, by fetching it from its message queue. On the contrary,
PostMessage doesn't call the window procedure. Instead it adds a MSG structure to the
message queue of the thread or process of the application window (to whom the message
has to be passed) and returns. The thread or application processes the message when it
gets around to it.
We should use SendMessage to send messages to an application window to perform some
action that must be done immediately. Whereas, use Postmessage for messages that are
not urgent.
How do I write code, to display a toolbar at the left edge of the window, moreover,
the buttons on the toolbar should get arranged in multiple rows and should work
like check box?
Ans: This is shown in following code fragement.
int CMainFrame :: OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
// AppWizard generated code
// Create tool bar with styles
m_tool.CreateEx ( this, TBSTYLE_BUTTON | TBSTYLE_WRAPABLE, WS_CHILD |
WS_VISIBLE | CBRS_SIZE_FIXED | CBRS_ALIGN_LEFT, CRect ( 0, 0, 5, 5 ), 1 ) ;
m_tool.SetWindowText ( "Tool" ) ;
// Create imgaelist & set it
// IDB_BITMAP1 is ID of bitmap holding images of toolbar buttons, & created in
resource
CImageList img ;
img.Create ( IDB_BITMAP1, 22, 0, RGB ( 255, 0, 255 ) ) ;
m_tool.GetToolBarCtrl( ).SetImageList ( &img ) ;
img.Detach( ) ;
// Add button information
m_tool.SetButtons ( NULL, 6 ) ;
// ID_B1 to ID_B6 are #define macros added for buttons
m_tool.SetButtonInfo ( 0, ID_B1, TBSTYLE_GROUP | TBSTYLE_CHECKGROUP, 0 ) ;
m_tool.SetButtonInfo ( 1, ID_B2, TBSTYLE_CHECKGROUP, 1 ) ;
m_tool.SetButtonInfo ( 2, ID_B3, TBSTYLE_CHECKGROUP, 2 ) ;
m_tool.SetButtonInfo ( 3, ID_B4, TBSTYLE_CHECKGROUP, 3 ) ;
m_tool.SetButtonInfo ( 4, ID_B5, TBSTYLE_CHECKGROUP, 4 ) ;
m_tool.SetButtonInfo ( 5, ID_B6, TBSTYLE_CHECKGROUP, 5 ) ;
// Set Toolbar size
CRect toolrect,r ;
m_tool.GetItemRect ( 0, &toolrect ) ;
m_tool.SetSizes ( toolrect.Size( ), CSize ( 22, 20 ) ) ;
// Set number of rows
m_tool.GetToolBarCtrl( ).SetRows ( 3, TRUE, &r ) ;
// Code to dock toolbar
m_tool.EnableDocking ( CBRS_ALIGN_ANY ) ;
EnableDocking ( CBRS_ALIGN_ANY ) ;
DockControlBar ( &m_tool ) ;
return 0 ;
}
Here, we have created a toolbar with style as TBSTYLE_BUTTON and TBSTYLE_WRAPABLE.
These two styles indicate that the toolbar contains buttons and can have multiple rows of
buttons respectively. The SetRows( ) function is used to set the number of rows for
buttons.
How do I get the text in resources like menu, toolbar etc, in some different
language like German?
Ans: While creating project, in Step 1, AppWizard displays a combo-box under the name
"What language would you like your resources in?" From this combo-box select the
language that you want. This would add text for the resources in the language that you
have selected.
How do I create a pen so that the joins of the shapes appear round?
Ans: Create a pen as shown in the following code snippet:
CChildView :: OnPaint( )
{
LOGBRUSH lb ;
lb.lbStyle = BS_SOLID ;
if ( f.IsDots( ) )
continue ;
if ( fname == m_path && f.IsDirectory( ) )
{
MessageBox ( "Directory exists..." ) ;
flag = 1 ;
break ;
}
if ( !flag )
MessageBox ( "Directory does not exist..." ) ;
How do I associate multiple file extensions with the same document class?
Ans: In applications like Notepad and MS-Word we can open files with different file
extensions. For example, in Notepad we can open a '.txt' file as well as '.htm' file. We can
also implement this feature in our MDI application. For this create a document template
object for each file extension that you want to use in your application. Here, we intend to
create two objects, one associated with '.txt' extension and the other with '.ini' extension.
Modify the InitInstance( ) function as shown below:
BOOL CMultiextApp::InitInstance( )
{
// AppWizard added code
CMultiDocTemplate* pDocTemplate ;
pDocTemplate = new CMultiDocTemplate ( IDR_MULTIETYPE, RUNTIME_CLASS
( CMultiextDoc ), RUNTIME_CLASS ( CChildFrame ), RUNTIME_CLASS
( CMultiextView ) ) ;
AddDocTemplate ( pDocTemplate ) ;
CMultiDocTemplate* pDocTemplate1 ;
pDocTemplate1 = new CMultiDocTemplate ( IDR_TEXTTYPE,
RUNTIME_CLASS(CMultiextDoc), RUNTIME_CLASS ( CChildFrame ), RUNTIME_CLASS
( CMultiextView ) ) ;
AddDocTemplate ( pDocTemplate1 ) ;
// AppWizard added code
return TRUE;
}
For each object all the parameters except the resource ID must be same. We have kept the
default resource ID for '.ini' file. Create a resource string having ID IDR_TEXTTYPE for the
'.txt' file. Also add the icon and menu having ID IDR_TEXTTYPE. Modify the string so that it
contains suitable filterName and filterExt substrings. Now you can create or open both the
text files and ini files.
if ( cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew
|| cmdInfo.m_nShellCommand == CCommandLineInfo::FileNothing )
{
CString docname = GetProfileString ( "Settings", "LastDocName", "" ) ;
if ( !docname.IsEmpty( ) )
OpenDocumentFile ( docname ) ;
}
Why should we restore the device context by selecting the old GDI object once we
have used it?
Ans: If we select a new pane or brush in the device context after its use is over we must
restore the old brush in the device context. Following code snippet shows how to do this:
CPen mypen ( PS_SOLID, 1, RGB ( 255, 0, 0 ) ) ;
CClientDC dc ( this ) ;
CPen *oldpen = dc.SelectObject ( &mypen ) ;
// Use pen
mypen.DeleteObject( ) ;
dc.SelectObject ( &oldpen ) ;
When we select a GDI object, pen in this case, by calling SelectObject( ) function, address
of the pen gets stored in the device context structure. When we call DeleteObject( )
function, the pen gets deleted but its address remains stored in the device context
structure. That pointer points to such a location which does not exist at all. Such a pointer is
called as dangling pointer. Hence after deleting our pen it is necessary to restore the
address of the old pen previously selected.
base classes in our VC++ application. For this, open VC++ project in VC++.NET
environment. In the Solution Explorer window, right click on the name of project and select
'Properties' option. In C/C++ tab, in the 'General' link, change the 'Compile As Managed'
option to 'Assembly Support (/clr)'.
Following code shows how to use .NET collection classes.
#pragma push_macro("new")
#undef new
#using <mscorlib.dll>
#using <System.dll>
using namespace System ;
using namespace System::Collections ;
void CbaseclassView::display( )
{
ArrayList *a = new ArrayList ( 5 ) ;
// Add items in list
String *s ;
CClientDC d ( this ) ;
IEnumerator *e = a -> GetEnumerator( ) ;
int y = 30 ;
while ( e -> MoveNext( ) )
{
s = ( e -> Current ) -> ToString( ) ;
d.TextOut ( 10, y+=50, s ) ;
}
#pragma pop_macro("new")
How would you detect in your application that the system settings have been
changed?
Ans: Whenever the system settings such as folder options, active desktop settings, desktop
style, etc. change, Windows sends WM_SETTINGCHANGE message to all the top-level
windows. We can handle this message in our application and detect that the settings have
changed. The OnSettingChange( ) handler is shown below:
void CMainFrame::OnSettingChange ( UINT uFlags, LPCTSTR lpszSection )
{
MessageBox ( "Settings are changing" ) ;
CFrameWnd::OnSettingChange ( uFlags, lpszSection ) ;
}
How do I write code that displays a button on status bar and clicking the button
displays a bitmap besides the button on the status bar?
Ans: Follow the steps listed below:
10
6. Add following entry to the message map so that on clicking the button the
ShowBitmap( ) function gets executed.
ON_COMMAND ( 100, ShowBitmap )
How does the CDC member functions like DrawText( ) and TextOut( ) receives
both a char* as well as a CString?
Ans: DrawText( ) and TextOut( ) are overloaded to receive char* and CString. Its not
that char* is converted to CString while receiving. This has been done so because CString
is accepted by the overloaded function as a reference. This saves copying overhead. Had it
received a CString by value there would have been no need for overloading.
------------------------------------------------------------------------------------------------------What happens if we pass a CString to a function that expects LPCSTR or viceversa?
Ans: If you pass a CString to a function that expects LPCSTR, then because CString has a
conversion operator, CString::operator LPCSTR, that converts the CString to an LPCSTR.
All the compiler needs to know is that there's this member function called operator
LPCSTR (operator const char*) that returns LPCSTR.
Now, if you pass a LPCSTR to a function that expects a CString, then again one of the
functions defined for CString as CString::CString(LPCSTR), gets called. This is a
constructor that creates a CString from an LPCSTR.
11
When we create a modeless dialog we allocate memory dynamically for the object
of the desired dialog class. How do I write code to display only one instance of the
modeless dialog and to de-allocate memory?
Ans: The memory allocated dynamically for the dialog class would not get de-allocated
unless we call delete operator. Suppose a modeless dialog of class mydialog has to be
displayed by calling a function of CChildView class, then follow the steps given below:
1. Add a pointer to an object of the mydialog class as a private data member to
CChildView class.
2. Initialize this data member to NULL in the constructor of CChildView class.
3. Add code shown below to the function that displays modeless dialog.
void CChildView :: OnModelessdlg( )
{
if ( d== NULL )
{
d = new mydialog ( this ) ; // where mydialog is a class
d -> Create ( IDD_DIALOG1 ) ; // where IDD_DIALOG1 is an ID of the dialog
created in resource editor
d -> ShowWindow ( 1 ) ;
}
else
d -> SetFocus( ) ; // to activate the dialog which is already created
}
Here, first we have ascertained whether the pointer d is NULL. If it is, then we have
allocated memory dynamically, passed the address of parent window (i.e. CChildView
class) to the constructor of mydialog class. Then we have created dialog and displayed it. If
the pointer d is not NULL then we have activated the dialog by calling SetFocus( ) so that
the same dialog would get activated.
4. Add a pointer to CWnd class as a data member to dialog class and collect the parent
address received by constructor in it.
5. Add handlers for 'OK' and 'Cancel' button to the mydialog class. A modeless dialog never
gets dismissed by calling EndDialog( ) hence, delete the base class handlers called in
OnOK( ) or OnCancel( ), and call DestroyWindwo( ) function in each of them.
6. Override PostNcDestroy( ) (a virtual function) in the mydialog class and call a user
defined function say delptr( ) of CChildView class as shown below:
void mydialog::PostNcDestroy( )
{
( CChildView * ) p ) -> delptr( ) ;
CDialog::PostNcDestroy( );
}
7. Add a function delptr( ) to CChildView class and enter following code to it.
voif CChildView :: delptr( )
{
delete d ;
d = NULL ;
}
12
How do I write code that would restrict user from entering any digits in an edit
control?
Ans: Follow the steps given below:
1.
2.
3.
4.
13
// AppWizardGenerated code
How can I create an edit window of the size same as the size of frame window and
resize automatically when size of frame window is changed?
Ans: By giving AFX_IDW_PANE_FIRST as an id while creating an edit window.
For example:
edit.Create ( WS_CHILD | WS_VISIBLE | ES_MULTILINE, rectDefault, this,
AFX_IDW_PANE_FIRST ) ;
where edit is an object of CEdit class.
We can get the memory information of the machine like total virtual memory, memory in
use, etc using an API function GlobalMemoryStatus( ) as shown below:
void mydialog::OnButton1( )
{
DWORD var ;
14
MEMORYSTATUS memorystatus = { 0 } ;
memorystatus.dwLength = sizeof ( MEMORYSTATUS ) ;
GlobalMemoryStatus ( &memorystatus ) ;
CString m_memused ;
m_memused.Format ( "Memory used %ld",
memorystatus.dwMemoryLoad ) ;
var = memorystatus.dwTotalPhys / 1024 ;
CString m_meminstalled ;
m_meminstalled.Format ( "Memory installed %ld", var ) ;
m_meminstalled += " KB" ;
var = memorystatus.dwAvailPhys / 1024 ;
CString m_memavailable ;
m_memavailable.Format ( "Memory available %ld", var ) ;
m_memavailable += " KB" ;
var = memorystatus.dwTotalVirtual / 1024 ;
CString m_memvirtual ;
m_memvirtual.Format ( "Total virtual memory %ld", var ) ;
m_memvirtual += " KB" ;
CString meminfo ;
meminfo = m_memused ;
meminfo += "\n" ;
meminfo += m_meminstalled ;
meminfo += "\n" ;
meminfo += m_memavailable ;
meminfo += "\n" ;
meminfo += m_memvirtual ;
MessageBox ( meminfo ) ;
}
15
16
return TRUE ; // return TRUE unless you set the focus to a control
The SetBkImage( ) function makes use of OLE COM functionality. Hence we have called
CoInitialize( ) to initialise the COM libraries.
In an MDI application that supports multiple document types, how does a view
identify its document?
Ans: A document object can have any number of views associated with it, but a view always
belongs to just one document. The framework stores a pointer to the associated document
object in a view's m_pDocument data member and exposes that pointer through the
view's GetDocument( ) member function. The way document object can identify its views
using GetFirstViewPosition( ) and GetNextView( ), a view can identify its document by
calling the GetDocument( ) function.
How do I write code that sets desktop wallpaper using IActiveDesktop interface?
Ans: Create a dialog based application, and #include following header files in 'StdAfx.h'
file. Note that the following files should get #included after 'afxwin.h'
#include <comdef.h>
#include <wininet.h>
#include <atlbase.h>
Then add a private variable to the dialog class as shown below:
CComQIPtr<IActiveDesktop> pad ;
To get interface pointer add following code to OnInitDialog( ).
BOOL CSetwpDlg :: OnInitDialog( )
{
// AppWizard generated code
CoInitialize ( NULL ) ;
HRESULT hr = CoCreateInstance ( CLSID_ActiveDesktop, NULL,
CLSCTX_INPROC_SERVER, IID_IActiveDesktop, ( void** ) &pad ) ;
return TRUE ;
}
To set wallpaper add following code to the button handler.
void CSetwpDlg::OnSetwallpaper( )
{
COMPONENTSOPT comopt ;
WALLPAPEROPT wpopt ;
comopt.dwSize = sizeof ( comopt ) ;
17
comopt.fActiveDesktop = TRUE ;
comopt.fEnableComponents = TRUE ;
wpopt.dwSize = sizeof ( WALLPAPEROPT ) ;
wpopt.dwStyle = WPSTYLE_TILE ;
pad -> SetDesktopItemOptions ( &comopt, 0 ) ;
pad -> SetWallpaperOptions ( &wpopt, 0 ) ;
USES_CONVERSION ;
CString str = "C:\\Winnt\\Soap Bubbles.bmp" ;
pad -> SetWallpaper ( T2CW ( str ), 0 ) ;
pad -> SetWallpaperOptions ( &wpopt, 0 ) ;
pad -> ApplyChanges ( AD_APPLY_ALL ) ;
}
18
return TRUE ;
How to ensure that at a time only one instance of an application runs in the
memory?
Ans: Some applications like MS-Power Point allow only one instance of the application to run
in the memory. It means that if PowerPoint application is already loaded and if we try to
open another '.ppt' file the file gets opened in the same instance of PowerPoint. We can also
achieve this using the following code.
In the frame window class write a function as shown below:
int CMainFrame::oncheck( )
{
return 0xA1B2C3D4 ;
}
Nothing special about the number 0xA1B2C3D4. We can give any unique number.
Make the following entry in message map of frame window class.
ON_MESSAGE ( WM_USER, oncheck )
BOOL CMyApp::InitInstance( )
{
19
How do I write code so that when focus is set on edit control, its background and
foreground color changes and when the focus is not on the edit control, it should
change back to normal?
Ans: To change color of edit control when focus is set on it and bring it back to normal when
focus goes on some other control, create a class derived from CEdit and handle
EN_SETFOCUS and EN_KILLFOCUS events in it. Besides this also handle WM_CTLCOLOR
message in this class. Add code to the event handlers as shown below:
HBRUSH MyEdit :: CtlColor ( CDC* pDC, UINT nCtlColor )
{
if ( CWnd :: GetFocus( ) == this )
{
static CBrush mybrush ( RGB ( 255, 0, 0 ) ) ;
pDC -> SetBkColor ( RGB ( 0, 255, 0 ) ) ;
pDC -> SetTextColor ( RGB ( 0, 0, 255 ) ) ;
return mybrush ;
}
return NULL ;
}
void MyEdit :: OnSetfocus( )
{
Invalidate( ) ;
UpdateWindow( ) ;
}
void MyEdit :: OnKillfocus( )
{
Invalidate( ) ;
UpdateWindow( ) ;
}
Now add a member variable of MyEdit class to the dialog class of your dialog-based
application. Also add an edit control on to the dialog template. To subclass this control add
code to OnInitDialog( ) as shown below:
BOOL CMyDlg :: OnInitDialog( )
{
20
DeleteContents( )...
21
In case of an SDI application, when a new document is created or opened, the framework
calls the virtual function DeleteContents( ) to delete the document's existing data. Thus,
we can override CDocument::DeleteContents( ) and take the opportunity to free any
resources allocated to the document and perform other necessary cleanup procedures, in
order to reuse the document object.
Collection Classes
Ans: MFC provides collection classes of three categories. The classes under each category
and what the object of these classes can store are given below:
MFC Array Classes
CByteArray - 8-bit bytes (BYTEs)
CWordArray - 16-bit words (WORDs)
CUIntArray - Unsigned integers (UINTs)
CStringArray - CStrings
CPtrArray - void pointers
CObArray - CObject pointers
MFC List Classes
CObList - CObject pointers
CPtrList - void pointers
CStringList - CStrings
MFC Map Classes
CMapWordToPtr - Stores void pointers keyed by WORDs
CMapPtrToWord - Stores WORDs keyed by void pointers
CMapPtrToPtr - Stores void pointers keyed by other void pointers
CMapWordToOb - Stores CObject pointers keyed by WORDs
CMapStringToOb - Stores CObject pointers keyed by strings
CMapStringToPtr - Stores void pointer keyed by strings
CMapStringToString - Stores strings keyed by other strings
22
RUNTIME_CLASS ( )...
The RUNTIME_CLASS macro surrounding the class names returns a pointer to a
CRuntimeClass structure for the specified class. This enables the framework to create
objects of that class at run time. This is what is a dynamic creation mechanism a feature of
Doc/View.
How would you display a list box having a check box in front of each item?
Ans: We come across a list box having check boxes many times while installing softwares
like Microsoft Visual C++, MS-office etc. We can also implement such a list box and give a
professional look to our application. This is how it can be done...
Run the application and you will see the list control with check boxes. You can
interact with the control using member functions of CCheckListBox.
23
How to extract red, green and blue elements from a RGB value without using API
functions?
Ans: Following code retrieves red, green and blue elements from a COLORREF object rgb.
COLORREF rgb = RGB ( 100, 50, 75 ) ;
int r, g, b ;
r = ( ( rgb ) & 0xff ) ;
g = ( ( ( rgb ) >> 8 ) & 0xff ) ;
b = ( ( ( rgb ) >> 16 ) & 0xff ) ;
Suppose there are 6 pairs of controls, each having a slider control and an edit
control. If slider of a particular slider control is moved then the value
corresponding to its position should get displayed in an edit control placed besides
it. How do I write code to achieve this?
24
Ans: Override OnNotify( ) virtual function. This function notifies the parent window of a
control that an event has occurred in the control. Add code to it as shown below:
BOOL CMyDlg :: OnNotify ( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
NMHDR *n = ( NMHDR * ) lParam ;
switch ( n -> idFrom )
{
case IDC_SLIDER1 :
m_val1 = m_slider1.GetPos( ) ;
break ;
// where m_val1 is a value var. of edit ctrl.
// & m_slider1 is a ctrl var. of slider ctrl.
case IDC_SLIDER2 :
m_val2 = m_slider2.GetPos( ) ;
break ;
case IDC_SLIDER3 :
m_val3 = m_slider3.GetPos( ) ;
break ;
case IDC_SLIDER4 :
m_val4 = m_slider4.GetPos( ) ;
break ;
case IDC_SLIDER5 :
m_val5 = m_slider5.GetPos( ) ;
break ;
case IDC_SLIDER6 :
m_val6 = m_slider6.GetPos( ) ;
break ;
}
UpdateData ( FALSE ) ;
return CDialog :: OnNotify ( wParam, lParam, pResult ) ;
}
How do I write code so that if I delete a file, then instead of getting the file
deleted permanently it should go to the Recycle bin?
Ans: Use a shell API function called SHFileOperation( ). This function takes one argument
which is a pointer to the SHFILEOPSTRUCT structure. This structure tells Windows what
operation to perform, which files to delete, and other important information.
SHFileOperation( ) also lets us copy, move, or rename one or several files. The following
code snippet shows how to use this function.
void CRecycleDlg::OnDelete()
{
static SHFILEOPSTRUCT fp ;
char buff[] = "C:\\file1.txt\0\0" ;
fp.wFunc = FO_DELETE ;
fp.pFrom = ( LPCSTR ) buff ;
fp.fFlags = FOF_ALLOWUNDO ;
}
SHFileOperation ( &fp ) ;
25
If I add a new class, say myview, for example derived from CListView, the
ClassWizard generates a class but uses DECLARE_DYNCREATE(...) and declares
constructor as protected. Now, if I try to create an instance of the class, I get the
compiler error as "cannot access protected member declared in class 'myview'?
Why does ClassWizard makes the constructor protected?
Ans: The ClassWizard makes the constructor of class as protected, this is because the
framework normally creates an object. If this is a CView derived class, normally the
CDocumentTemplate instantiates the view during the default OnFileNew( ) or when you
call OpenDocumentFile( ). The framework does this so that it will give you an error
message if you accidentally try to instantiate it yourself. If you really need to do
instantiation outside of the CDocTemplate framework, simply change the constructor to be
public.
Can we have drag-drop functionality for a CListBox control? If yes then how do I
get the name(s) of file(s) that I drag-drop on a CListBox control?
Ans: The CListBox control can have a drag-drop functionality. Follow the steps given below
to get the names of files dropped on a list box.
1. Create a dialog-based application. Add a list box control to the dialog template.
2. Check 'Accept Files' property of the 'Extended Styles' tab for the list box control, so that if
a user drops a file on this control, WM_DROPFILES message will be sent to the control.
3. Add a new class say list derived from CListBox class to the application.
4. Add WM_CREATE and WM_DROPFILES message handlers to the list class and enter code
given below to these handlers.
int list :: OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
//AppWizard generated code
DragAcceptFiles ( TRUE ) ;
return 0 ;
}
void list :: OnDropFiles ( HDROP hDropInfo )
{
char buff[255] ;
int c = DragQueryFile ( hDropInfo, 0xFFFFFFFF, ( LPTSTR ) buff, sizeof ( buff ) ) ;
for ( int i = 0 ; i < c ; i++ )
{
int c = DragQueryFile ( hDropInfo, i, ( LPTSTR ) buff, sizeof ( buff ) ) ;
AddString ( ( LPCTSTR ) buff ) ;
}
}
26
The function CWnd::FindWindow( ) identifies the window with the class Shell_TrayWnd.
Then to get the pointer to the window we have called function CWnd::GetWindow( ).
27
Next, to move the button, we require to know the screen coordinates of the upper-left and
lower-right corners of the start button. This is achieved by calling
CWnd::GetWindowRect( ) function. These coordinates are then converted to the client
coordinate as they are required to place the start button at new place. Then to move start
button we should know the maximum width (in terms of pixels) of the display monitor. The
function GetSystemMetrics( ) would give us the width of the screen. Then we have called
a timer, that would move the start button
CMyDialog::OnTimer ( UINT nIDEvent )
{
rect.OffsetRect ( 1, 0 ) ;
if ( rect.left >= m_maxX )
rect.left = 2 ;
m_pWndStart -> SetWindowPos ( &wndTop, rect.left, rect.top, 0, 0, SWP_NOSIZE |
SWP_SHOWWINDOW | SWP_FRAMECHANGED ) ;
}
The function CRect::OffsetRect( ) would move the Start button by one unit to the right (of
start button on the taskbar). CWnd::SetWindowPos( ) would change the position of the
window.
28
elements like caption bar, menu, desktop, etc of a window. This function takes the number
of elements whose color has to be changed, a pointer to an array of integers which
represents the display elements, and an array containing new RGB values for the elements
whose color has to be changed. The following code snippet demonstrates the use of this
function, where we have changed the color of caption bar of active window, menu and a
window.
void CSyscolorDlg::OnSetColor( )
{
int color_array[] = { COLOR_ACTIVECAPTION, COLOR_MENU, COLOR_WINDOW } ;
COLORREF rgbvalues[] = { RGB ( 255, 0, 0 ) , RGB ( 255, 255, 0 ), RGB ( 0, 255,
255 ) } ;
SetSysColors ( 3, color_array, rgbvalues ) ;
}
29
// check if the toolbutton for whom the drop dwon menu has to be displayed is
selected
if ( lpnmTB -> iItem == ID_MY_BUTTON )
{
if ( menu.m_hMenu != NULL )
menu.DestroyMenu( ) ;
menu.LoadMenu ( IDR_MENU1 ) ;
CMenu* pPopup = menu.GetSubMenu ( 0 ) ;
p.x = r.top ;
p.y = r.bottom ;
pPopup -> TrackPopupMenu ( TPM_RIGHTALIGN | TPM_RIGHTBUTTON, p.x, p.y,
this ) ;
return FALSE ; //indicates the TBN_DROPDOWN notification was handled.
}
}
How do I write code that sets different icon for all the modeless dialogs of my
application?
Ans: To set a different icon for a modal/modeless dialog, call SetIcon( ) in
OnInitDialog( ) of each of the dialog class for which an icon has to be set. This is shown in
the code snippet given below:
BOOL modeless :: OnInitDialog( )
{
CDialog :: OnInitDialog( ) ;
SetIcon ( AfxGetApp( ) -> LoadIcon ( IDI_ICON1 ),FALSE ) ;
}
return TRUE ;
30
DWORD flag ;
CString str = "" ;
if ( InternetGetConnectedState ( &flag, NULL ) )
str += "Internet connection is present\n" ;
else
str += "No Internet connection\n" ;
CreateCompatibleDC( )...
To draw a bitmap in a window, first we have to create a special type of device context called
memory device context and then select the bitmap into the memory device context.
CDC::CreateCompatibleDC( ) creates a memory DC that is compatible with the specified
device context whose address you pass in is usually a screen DC.
Once a bitmap is selected into a memory device context, we can draw to the memory device
context using the same CDC member functions you use to draw to a screen or printer
device context. Drawing to a memory device context first and then transferring them to a
screen device context can be useful for replicating the same image on the screen several
times. Rather than draw the image a new each time, you can draw it once in a memory
device context and then transfer it to a screen device context as many times as you want.
The width and height of a widow of an SDI application is fixed so that it cannot be
changed at runtime. However, if I move cursor on the left or right border of the
window, it still displays the left/right size arrows. How do I write code to prevent
the size arrows from getting displayed?
Ans: To prevent displaying of size arrows for a window whose size has been fixed override
WM_NCHITTEST message in your application as shown below:
UINT CMainFrame :: OnNcHitTest ( CPoint point )
{
31
default :
return hittest ;
}
The OnNcHitTest( ) function returns an enumerated value. For example a value such as
HTBORDER indicates that the mouse is on the broder of the window.
Here, we have checked the value returned by the CFrameWnd::OnNcHitTest( ) function.
If the value is any from
HTLEFT/HTTOPLEFT/HTBOTTOMLEFT/HTRIGHT/HTTOPRIGH/HTBOTTOMRIGHT (which
require size arrow cursor) then we are returning HTBORDER that indicates no sizing border,
hence cursor will not get changed.
return FALSE ; // return TRUE unless you set the focus to a control
The AutoLoad( ) function internally loads the bitmap images and attaches them to
the button control.
32
Why do we get strange and misleading errors while running the program involving
typeid on VC++ 6.0 compiler?
Ans: The errors occur because we may not have enabled the RTTI option. To overcome
these errors we need to perform the following steps.
1. Select Settings from the Project menu and click the C/C++ tab
2. From the category listbox, select C++ language
3. Click the checkbox named Enable Run-time Type Information
33
}
Here, we have declared pfunc as a pointer to the SHFormatDrive( ) function. This
function takes 4 parameters - a handle of the dialog's (dialog that gets displayed by
SHFormatDrive( ) function) parent window, the drive number (0 for A:, 1 for B:, etc.), the
size of the formatted disk, a type indicating format type as quick or full format. Next, we
have loaded 'shell32.dll' file by calling the ::LoadLibrary( ) function and stored its return
value in the m_hinst object. We have then obtained the address of the SHFormatDrive( )
function by calling the ::GetProcAddress( ) function. We have then called the
SHFormatDrive( ) function using pfunc. On execution, this function will format A drive.
If CFile class is used to work on a file, then how to read a file till its end of file is
encountered (EOF)?
Ans: To check for end-of-file, we will have to check whether the number of bytes actually
read is less than the number of bytes requested. This is shown in the following code snippet.
CFile f ;
f.Open( ) ;
char buf[254] ;
UINT nread ;
do ( nread = f.read ( buf, 254 ) )
{
...
// process nread bytes
} while ( nread = 254 ) ;
34
window whenever a particular event occurs. For this, firstly #define a message as shown
below:
#define WM_MYMSG (WM_USER + 1)
Add a message map entry as shown below:
WM_MESSAGE ( WM_MYMSG, OnMyMsg )
OnMyMsg( ) is a user-defined function that will get called whenever the message
WM_MYMSG is sent to our window. Define this function as given below:
int CMessageDlg::OnMyMsg( )
{
MessageBox ( "Message Received" ) ;
}
return 0 ;
Is there any way by which I can increase/decrease the limit of amount of text an
edit control can hold?
Ans: The CEdit and CEditView classes have limits on the amount of text they can contain.
But, these limits are operating-system dependent. To adjust the limit we can use
CEdit::SetLimitText( ) function. We can also use CEdit::LimitText( ) function to limit the
length of the text that the user may enter into an edit control.
Windows 95 has a limit of 64 KB on edit controls and it cannot be increased. Windows NT
has a machine-dependent limit on edit controls. If you need to use a control that is
expected to contain near or over 64 KB of data, use CRichEditCtrl or CRichEditView.
These classes wrap the rich edit Windows control.
35
hdc = dc.GetSafeHdc( ) ;
::SetBkColor( hdc , RGB ( 255, 0, 100 ) ) ;
CDialog::OnPaint( ) ;
How do I write code to right justify the entries displayed in columns of list
control?
Ans: To right justify the text in columns of list control use CListCtrl::InsertColumn( )
function as shown below:
m_list.InsertColumn ( 0, "Name", LVCFMT_RIGHT, 100 ) ; // where m_list is a control var. of
list control
36
In a Doc/View application, how the resources get loaded by specifying only one
ID, IDR_MAINFRAME?
Ans: The LoadFrame( ) function is called to create and load the frame window. The
LoadFrame( ) function calls the functions LoadMenu( ), LoadString( ), LoadIcon( ),
etc. and pass them the ID IDR_MAINFRAME. These functions search the resources having
ID IDR_MAINFRAME and a corresponding tag. For example, LoadMenu( ) function searches
for the resource IDR_MAINFRAME having tag MENU, the LoadIcon( ) function searches for
the resource IDR_MAINFRAME having tag ICON and so on. Under each tag the information
of that particular resource is stored. Using this information the resource is then loaded on
the frame window. You can open the '.rc' file and see the tags written in front of
IDR_MAINFRAME.
37
What is the difference between worker thread and user interface thread?
Ans: A worker thread is mainly created to perform background work. It doesn't have a user
interface.
A UI thread provides user interface and is created to interact with the user. You might use
UI threads in an application that creates several independent windows, each of which
occasionally needs to do extensive processing.
A worker thread is created by calling AfxBeginThread( ).
To create a UI thread you must derive a class from CWinThread and override its
InitInstance( ) function to create a window.
A worker thread does not have its own message loop.
A UI thread has its own message loop.
A worker thread executes for once and then terminates.
A UI thread terminates when it receives WM_QUIT message.
How to make sure that the application automatically opens the document that is at
the top of the recent file list?
Ans: #include the 'afxadv.h' file in the application class's source file. This file is required
for CRecentFileList class's definition. Add the following code in InitInstance( ) to open
the first file in MRU list.
BOOL CMRUApp::InitInstance( )
{
// AppWizard generated code
if ( cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew ||
cmdInfo.m_nShellCommand == CCommandLineInfo::FileNothing )
{
if ( m_pRecentFileList != NULL )
{
38
}
}
else
if ( !ProcessShellCommand ( cmdInfo ) )
return FALSE ;
}
What is a Hook?
Ans: A C programmer is often very excited when he creates his first TSR. A TSR is a
'Terminate but Stay Resident program' which continues to remain in memory even if the
program is terminated. One can use a TSR for number of purposes like displaying a clock on
output screen, keeping track of user's actions, etc. However, TSRs cannot run in Windows.
In Windows a TSR like activity is performed by Hook. A hook is a mechanism by which a
39
function can intercept events (messages, mouse actions, keystrokes) before they reach an
application. Following code snippet shows how to create a hook that intercepts the keyboard
events. Whenever a keyboard event occurs we set the status of the Caps Lock to off. As a
result, once this program is executed, there onwards any attempt to put on the Caps Lock
on would fail. This is because an attempt to put it on would result into transfer of control to
our filter function. And this function would put the Caps Lock off.
Declare a variable of type HHOOK as shown below:
HHOOK hookdata ;
Declare a global function which is called as a 'filter function'.
LRESULT CALLBACK KeyboardProc ( int code, WPARAM w, LPARAM l ) ;
In OnCreate( ) handler call the following statement.
int CMainFrame::OnCreate( )
{
// AppWizard added code
hookdata = SetWindowsHookEx ( WH_KEYBOARD, KeyboardProc, NULL, 0 ) ;
}
return 0 ;
SetWindowsHookEx( ) maintains the specified filter functions. Define the global filter
function as shown below:
LRESULT CALLBACK KeyboardProc ( int code, WPARAM w, LPARAM l )
{
if ( code < 0 )
return CallNextHookEx ( hookdata, code, w, l ) ;
unsigned char state [256] ;
if ( w == VK_CAPITAL )
{
GetKeyboardState ( state ) ;
if ( state [VK_CAPITAL] == 1 )
state [VK_CAPITAL] = 0 ;
SetKeyboardState ( state ) ;
}
return CallNextHookEx ( hookdata, code, w,1 ) ;
In case of COM, what is meant by aggregation and how do I get an interface of the
aggregated object?
Ans: Aggregation is the reuse mechanism, in which the outer object exposes interfaces
from the inner object as if they were implemented on the outer object itself. This is useful
when the outer object would always delegate every call to one of its interfaces to the same
interface in the inner object.
Aggregation is actually a specialized case of containment/delegation, and is available as a
convenience to avoid extra implementation overhead in the outer object. We can get a
40
pointer to the interface, by calling QueryInterface( ) of the outer object with IID of the
inner interface.
Can we get the name of the current DLL where an exported function lives?
Ans: The function GetModuleFileName( ) gives the name of a module (which is a DLL or
an EXE). This function takes two arguments, a handle to the instance of the module
HINSTANCE, and a buffer to store the name of the module. If we call the
GetModuleFileName( ) function with a NULL as an instance handle, it would return the
name of the module running, which is an EXE, not the DLL. To get the name of DLL an
instance handle is required.
To get an instance handle we can use AfxGetAPP( ) function. This function returns a
pointer to the current global application object. Then pass m_hInstance a member of
CWinApp class, to the GetModuleFileName( ) function. Follow the steps given below.
1. Create an application to form '.dll' file.
2. Override the InitInstance( ) function in the application class of the module, that
creates '.dll'. Enter following code to the InitInstance( ) function.
BOOL CFontdllApp::InitInstance()
{
// Appwizard generated code
char str[ 100 ] ;
::GetModuleFileName ( AfxGetApp( ) ->m_hInstance , str, sizeof ( str ) ) ;
AfxMessageBox ( str ) ;
return CWinApp::InitInstance( ) ;
}
If you run the application in which the above given '.dll' file is getting used, then a message
box would get displayed with the full name of the '.dll' file being used.
Many a times we create a control and need to reuse it in number of other applications.
Instead of creating the class having the same functionality or copying the already created
classes we can add the created control to the in-built gallery of controls. We can then add
this control to the project as and when necessary. Following steps show how to achieve this.
41
Add the control by selecting 'Project | Add to Project | Component and Control |
mycontrol'. Select 'charedit.ogx' from there.
The 'charedit.h' and 'charedit.cpp' would get added to your project. Create the edit
control by calling charedit::Create( ) function.
How do I write code to get the index of the first selected item of a list control?
Ans: Use CListCtrl::GetNextItem( ) function as shown below:
void CMyDlg :: OnSelect( )
{
int iItem = m_list.GetNextItem ( -1, LVNI_SELECTED ) ;
if ( iItem == -1 )
MessageBox ( "No item selected..." ) ;
else
{
CString s ;
s.Format ( "Index of the first selected item is %d", iItem ) ;
MessageBox ( s ) ;
}
}
42
The path of executable file in which 'credits.htm' would get opened is returned in the last
parameter.
How do I write code to get the item of the list control that has focus?
Ans: To get the item that has focus use CListCtrl::GetNextItem( ) function as shown in
following code snippet.
void MyDlg :: OnSelect( )
{
int iItem = m_list.GetNextItem ( -1, LVNI_FOCUSED ) ; // where m_list is control
var. of list control
}
How do I write code to add a resizable status bar on a resizable dialog box?
Ans: Follow the steps given below:
1. Create a dialog-based application
2. Add a pointer to CStatusBar class as a data member to the dialog class
3. Open OnInitDialog( ) function and add code shown below to it.
BOOL CDlgstatDlg::OnInitDialog( )
{
// AppWizard generated code
// Create the status bar.
HWND h = CreateWindowEx ( 0, STATUSCLASSNAME,
(LPCTSTR) NULL, SBARS_SIZEGRIP | WS_CHILD,
0, 0, 0, 0, m_hWnd, 0, AfxGetApp( ) -> m_hInstance,
NULL ) ;
// Get the coordinates of the parent window's client area.
CRect r ;
GetClientRect ( &r ) ;
// allocate memory for the panes of status bar
int nopanes = 5 ;
int *indicators = new int[nopanes] ;
// set width for the panes
int width = r.right / nopanes ;
for ( int i = 0; i < nopanes ; i++ )
{
indicators[i] = width ; width += width ;
}
// Collect address in pointer to CStatusBar and call functions to set style
m_st = ( CStatusBar * ) CStatusBar::FromHandle ( h ) ;
m_st -> SendMessage ( SB_SETPARTS, (WPARAM) nopanes, (LPARAM) indicators) ;
m_st -> SendMessage ( SB_SETTEXT, (WPARAM) 0 | SBT_POPOUT, (LPARAM)
"Ready" ) ;
m_st -> ShowWindow ( 1 ) ;
return TRUE ;
43
}
4. To set pane text add a virtual function PreTranslateMessage( ) and enter code shown
below to it.
BOOL CDlgstatDlg::PreTranslateMessage(MSG* pMsg)
{
if ( pMsg->message == WM_KEYDOWN )
{
switch ( pMsg -> wParam )
{
case VK_CAPITAL :
m_st -> SendMessage ( SB_SETTEXT, (WPARAM) 1 | SBT_RTLREADING, (LPARAM)
"CAP" ) ;
break ;
}
}
return CDialog::PreTranslateMessage ( pMsg ) ;
}
5. To size the status bar when the dialog box resizes add handler for WM_SIZE message and
code shown below to it.
void CDlgstatDlg::OnSize ( UINT nType, int cx, int cy )
{
CDialog::OnSize ( nType, cx, cy ) ;
CRect r ;
m_st -> GetWindowRect ( &r ) ;
r.right += cx ;
r.bottom += cy ;
m_st -> SetWindowPos ( &wndTop, r.left, r.top, r.Width( ),
r.Height( ), SWP_SHOWWINDOW ) ;
}
44
SetModifiedFlag( )...
SetModifiedFlag( ) should get called whenever the document's data is modified. This
function sets a flag inside the document object, that tells MFC that the document contains
unsaved data. This helps MFC to prompt the user before closing a document that contains
unsaved changes.
45
46
void CFileprDlg::OnShow( )
{
SHELLEXECUTEINFO sh ;
ZeroMemory ( &sh, sizeof ( sh ) ) ;
sh.cbSize = sizeof ( sh ) ;
sh.lpFile = "C:\\myfile.txt" ; // path of file for which 'Properties' dialog is to be
displayed
sh.lpVerb = "properties" ;
sh.fMask = SEE_MASK_INVOKEIDLIST ;
ShellExecuteEx ( &sh ) ;
}
How do I write code to keep the bottom line in a multiple-line edit control visible?
Ans: To keep the bottom line in a multiple-line edit control visible, we need to know the
total number of text lines added to the control. Once we get this number we can call
LineScroll( ) function of CEdit class to scroll text of a multiple-line edit control.
BOOL CMuleditDlg :: OnInitDialog( )
{
// AppWizard generated code
int c = 0 ;
CString str1, str2 ;
CStdioFile f ( "Readme.txt", CFile::modeRead ) ;
while ( f.ReadString ( str1 ) != FALSE )
{
str2 += str1 + "\r\n" ;
c++ ;
}
m_edit.SetWindowText ( str2 ) ; // where m_edit is a control variable for edit control
m_edit.LineScroll ( c ) ;
return TRUE ;
}
Here, through a while loop we have read the contents of 'Readme.txt' file and copied it to
the CString object str2. We have also counted the number of text lines read. Then after
adding the text into the edit control we have called LineScroll( ) function to scroll text
lines. Note that for the edit control added to the dialog template we must enable 'Auto
HScroll' and 'Auto VScroll' properties
47
}
Here, first we have added some strings (which are meanings of word 'String') to an object s
of CStringList class. Then we have created an object p of class CMapStringToOb.
CMapStringToOb is an MFC collection class which maps unique CString objects to
CObject pointers. Thus through the statement p["String"] = ( CObject * ) &s ; we have
mapped the address of s as a value to the key value 'string'. The Lookup( ) function called
next returns a reference to a CObject pointer (mapped with key 'String') which we have
collected in get. Lastly, to display the strings we have retrieved the position of first string by
calling GetHeadPosition( ) and then through a loop we have displayed the strings.
We can display a bitmap or a picture in our window using CDC's member functions. However
once a bitmap is displayed we cannot change its size like we do in MS-Word or MSPowerPoint. If you want that when user clicks the picture resize handles should appear and
on dragging the handle picture's size should change then use the functionality of
48
How do I write code, to display a toolbar at the left edge of the window, moreover,
the buttons on the toolbar should get arranged in multiple rows and should work
like check box?
Ans: This is shown in following code fragement.
int CMainFrame :: OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
// AppWizard generated code
// Create tool bar with styles
m_tool.CreateEx ( this, TBSTYLE_BUTTON | TBSTYLE_WRAPABLE, WS_CHILD |
WS_VISIBLE | CBRS_SIZE_FIXED |
CBRS_ALIGN_LEFT, CRect ( 0, 0, 5, 5 ), 1 ) ;
m_tool.SetWindowText ( "Tool" ) ;
// Create imgaelist & set it
// IDB_BITMAP1 is ID of bitmap holding images of toolbar buttons, & created in
resource
CImageList img ;
img.Create ( IDB_BITMAP1, 22, 0, RGB ( 255, 0, 255 ) ) ;
m_tool.GetToolBarCtrl( ).SetImageList ( &img ) ;
img.Detach( ) ;
// Add button information
m_tool.SetButtons ( NULL, 6 ) ;
// ID_B1 to ID_B6 are #define macros added for buttons
m_tool.SetButtonInfo ( 0, ID_B1, TBSTYLE_GROUP | TBSTYLE_CHECKGROUP, 0 ) ;
m_tool.SetButtonInfo ( 1, ID_B2, TBSTYLE_CHECKGROUP, 1 ) ;
m_tool.SetButtonInfo ( 2, ID_B3, TBSTYLE_CHECKGROUP, 2 ) ;
m_tool.SetButtonInfo ( 3, ID_B4, TBSTYLE_CHECKGROUP, 3 ) ;
m_tool.SetButtonInfo ( 4, ID_B5, TBSTYLE_CHECKGROUP, 4 ) ;
m_tool.SetButtonInfo ( 5, ID_B6, TBSTYLE_CHECKGROUP, 5 ) ;
// Set Toolbar size
CRect toolrect,r ;
m_tool.GetItemRect ( 0, &toolrect ) ;
m_tool.SetSizes ( toolrect.Size( ), CSize ( 22, 20 ) ) ;
// Set number of rows
m_tool.GetToolBarCtrl( ).SetRows ( 3, TRUE, &r ) ;
// Code to dock toolbar
m_tool.EnableDocking ( CBRS_ALIGN_ANY ) ;
EnableDocking ( CBRS_ALIGN_ANY ) ;
DockControlBar ( &m_tool ) ;
return 0 ;
}
Here, we have created a toolbar with style as TBSTYLE_BUTTON and TBSTYLE_WRAPABLE.
These two styles indicate that the toolbar contains buttons and can have multiple rows of
buttons respectively. The SetRows( ) function is used to set the number of rows for
buttons.
49
50
How do I write code to retrieve the text from column items of a list control?
Ans: Add a handler for NM_CLICK notification, that occurs when an item in the list control is
clicked with the left mouse button. Write code to this handler as shown below:
void MyDlg :: OnClickList1 ( NMHDR* pNMHDR, LRESULT* pResult )
{
NMLISTVIEW* nmitem = ( NMLISTVIEW* ) pNMHDR ;
LVHITTESTINFO lvhti ;
lvhti.pt = nmitem -> ptAction ;
lvhti.flags = LVHT_ONITEMLABEL ;
m_list.SubItemHitTest ( &lvhti ) ; // where m_list is a control var. for list control
CString m_text = m_list.GetItemText ( lvhti.iItem, lvhti.iSubItem ) ;
MessageBox ( m_text ) ;
}
The NMLISTVIEW structure used here contains information about the notification message
as well as about the item/subitem of the list control. The LVHITTESTINFO structure contains
information about a hit test. The member ptAction of NMLISTVIEW indicates the location at
which the event occurred. It contains the coordinates of the point at which the click
occurred. This point we have stored in pt, a data member of LVHITTESTINFO. Next, we
have set the flag of LVHITTESTINFO structure to LVHT_ONITEMLABEL which indicates that
the position is over a list-view item's text. Lastly, we have called SubItemHitTest( )
function which determines which list view item, if any, is at a given position. The parameter
that is to be passed to this function is a pointer to the LVHITTESTINFO structure. Then we
have retrieved the text by using the GetItemText( ) function.
51
How to fix the error "unexpected end of file while looking for precompiled header
directive" that occurs when compiling?
Ans: By default, the Visual C++ project wizard sets up a project to use 'Stdafx.h' as the
precompiled header file for every file in a project. All header files that are #included in
'StdAfx.h' are precompiled into a file named as 'projectname.pch' and 'stdafx.obj' so that
once compiled, they do not have to be compiled again. Appwizard #includes 'StdAfx.h' in
the CPP files that it generates and inside 'StdAfx.h', it adds #includes for MFC header files
such as 'AfxWin.h'. If a file however does not contain "#include <stdafx.h>", this message
is generated. To fix the problem, make sure that every '.cpp' of the project has #included
'StdAfx.h' header file.
How would you set an indicator in the caption bar indicating that the document is
dirty and needs to be saved?
Ans: While working in a VC++ source editor if you observe carefully, you would see that if
you make any changes in a file an indicator in the form of an asterisk ( '*' ) is shown in the
title bar indicating that the file is modified. If you save the file the indicator disappears. We
can also display such an indicator and remove it if user saves the document, by simply
overriding a virtual function SetModifiedFlag( ) in the document class as shown below:
void CTitleDoc::SetModifiedFlag ( BOOL bmodified )
{
CString title = GetTitle( ) ;
CString indicator = " *" ;
if ( !IsModified( ) && bmodified )
SetTitle ( title + indicator ) ;
52
else
{
if ( IsModified( ) && !bmodified )
{
title = title.Left ( title.GetLength( ) - indicator.GetLength( ) ) ;
SetTitle ( title ) ;
}
}
CDocument::SetModifiedFlag ( bmodified ) ;
}
Note that you must manually override the SetModifiedFlag( ) function without the help of
ClassWizard because although SetModifiedFlag( ) is a virtual function it is not mentioned
in the online help and if you right click the document class in ClassView tab and select 'Add
Virtual function' you would not see this function in the list of virtual functions.
How do I write code that displays button in various shapes which we select?
Ans: Derive a class say MyButton from CButton class and override DrawItem( ). This is
shown in the following code snippet:
void MyButton :: DrawItem ( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
CRect r = lpDrawItemStruct -> rcItem ;
CDC* dc = CDC::FromHandle ( lpDrawItemStruct -> hDC ) ;
UINT state = lpDrawItemStruct -> itemState ;
UINT nStyle = GetStyle( ) ;
int nSavedDC = dc -> SaveDC( ) ;
//make the rect a square
r.bottom = r.right = min ( r.bottom, r.right ) ;
//Draw button
switch ( sh )
{
case 1:
dc -> Ellipse ( r.left, r.top, r.right, r.bottom ) ;
break ;
case 2 :
dc -> MoveTo ( r.left, r.top ) ;
dc -> LineTo ( r.right, r.top ) ;
dc -> MoveTo ( r.right, r.top ) ;
dc -> LineTo ( r.right, r.bottom ) ;
dc -> MoveTo ( r.right, r.bottom ) ;
dc -> LineTo ( r.left, r.top ) ;
break ;
case 3 :
dc -> Rectangle ( r.left, r.top, r.right, r.bottom ) ;
break ;
}
}
Here sh is a member variable of MyButton class of type int. Then add a button control
onto the dialog template and set its 'Style' to 'Owner draw' & 'Flat'. Also add 3 radio buttons
53
labelled as 'Circle', 'Triangle' and 'Square' respectively. Now add code to OnInitDialog( ) of
the dialog class (of application) as shown below:
BOOL CButtonDlg :: OnInitDialog( )
{
m_bt.SubclassDlgItem ( IDC_BUTTON1, this ) ;
CDialog :: OnInitDialog( ) ;
// AppWizard generated code
}
Also add handlers for BN_CLICKED event for radio buttons and add code to them as shown
below:
void CButtonDlg :: OnRadio1( )
{
m_bt.sh = 1 ; // setting flag for shape
m_bt.Invalidate( ) ;
}
Similar code should go to the handlers for other two radio buttons.
How do I change title of 'Open' button in the standard File Open dialog box?
Ans: Follow the steps given below:
a) Derive a class from the CFileDialog class.
b) Add OnInitDialog( ) handler in the derived class and write the following code in it.
CWnd *p = GetParent( ) ;
CButton *b = ( CButton* ) p -> GetDlgItem ( IDOK ) ;
b -> SetWindowText ( "Delete" ) ;
The 'Open' button on the dialog box has an ID IDOK. We have passed this ID to the
GetDlgItem( ) to obtain the pointer to the 'Open' button. Using this pointer we have
changed the title.
Now, create an object of the derived class by passing appropriate parameters and call
DoModal( ). You will see the title of 'Open' button changed to 'Delete'.
Add command handlers for the buttons of the newly created toolbar.
54
How do I write code that allows to create a dynamic splitter at run time, i.e. when
we select an option like split window through a menu?
Ans: To create a dynamic splitter, override OnCreateClient( ) and add code to it as shown
below:
BOOL CMainFrame :: OnCreateClient ( LPCREATESTRUCT lpcs, CCreateContext* pContext )
{
m_dyn.Create ( this , 1 , 2 , CSize( 01 , 01 ) , pContext ) ; // where m_dyn is a member
variable of type CSplitterWnd
return TRUE ;
}
Here, we have simply created a dynamic splitter window of one row two columns. Then, to
the handler of menu item call DoKeyboardSplit( ) method of CSplitterWnd class as
shown below:
void CMainFrame :: OnSplit( )
{
m_dyn.DoKeyboardSplit( ) ;
}
SHFILEINFO...
The structure SHFILEINFO contains information about a file object. The elements of the
SHFILEINFO structure are as shown below.
typedef struct _SHFILEINFO
{
HICON hIcon ;
int iIcon ;
DWORD dwAttributes ;
char szDisplayName[MAX_PATH] ;
char szTypeName[80] ;
} SHFILEINFO ;
The element hIcon contains a handle to an icon that represents the file. The element iIcon
stores an index of the icon image (which is stored) within the system image list.
dwAttributes contains an array of values that indicates the attributes of the file object. The
name and type of the file is stored in szDisplayName and szTypeName respectively.
55
How do I write code that splits the client window statically into 3 panes (i.e. rows)
and further splits statically the second pane into 1 row 2 columns?
Ans: This shown in following code snippet:
BOOL CMainFrame :: OnCreateClient ( LPCREATESTRUCT lpcs, CCreateContext* pContext )
{
m_stat1.CreateStatic ( this, 3, 1 ) ;
m_stat2.CreateStatic ( &m_stat1, 1, 2, WS_CHILD | WS_VISIBLE , m_stat1.IdFromRowCol
( 1, 0 ) ) ;
m_stat1.CreateView ( 0, 0, RUNTIME_CLASS ( textview ), CSize ( 1, 1 ), pContext ) ;
m_stat1.CreateView ( 2, 0, RUNTIME_CLASS ( newview ), CSize ( 1, 1 ), pContext ) ;
m_stat2.CreateView ( 0, 0, RUNTIME_CLASS ( graphicsview ), CSize ( 1, 1 ), pContext ) ;
m_stat2.CreateView ( 0, 1, RUNTIME_CLASS ( newview ), CSize ( 1, 1 ), pContext ) ;
m_stat1.SetRowInfo ( 0, 100, 1 ) ;
m_stat1.SetRowInfo ( 1, 100, 1 ) ;
m_stat1.SetRowInfo ( 2, 100, 1 ) ;
m_stat2.SetColumnInfo ( 0, 200, 1 ) ;
m_stat2.SetColumnInfo ( 1, 200, 1 ) ;
return TRUE ;
}
Here, first statement creates static splitter window that splits the client window into 3 rows.
The second statement splits the 2 pane of static window into 2 panes. Then we have set the
views for the panes of static splitter windows and also set the row and column size of each
pane. Note that m_stat1, m_stat2 are the member variables of CMainFrame class of
type CSplitterWnd class.
56
Ans: We often enable/disable menu items. But if we have to disable the entire top-level
menu instead of a menu item we can do so using the following statements:
CMenu *m = GetMenu( ) ;
m -> EnableMenuItem ( 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED ) ;
The GetMenu( ) function returns pointer to the top-level menu. 0 mentioned in the
EnableMenuItem( ) function specifies to disable the zeroth top-level menu.
CRectTracker...
The CRectTracker class provides a user interface between rectangular items in an
application and the user by providing a variety of display styles. These styles include, solid,
hatched, or dashed borders; a hatched pattern that covers the item; and resize handles
that can be located on the outside or inside of a border. Trackers are often used in
conjunction with OLE items, that is, objects derived from COleClientItem.
In a dialog box how can I make sure that the dialog box does not get dismissed if
Esc key is pressed?
Ans: If a dialog box is displayed and Esc key is pressed, OnCancel( ) handler gets called
and the dialog gets dismissed. At times we want to take some other step when Esc key is
pressed. For example, if user has selected an item from a combo box we may want that his
selection should get cancelled if he presses Esc key. In this situation we cannot handle
WM_KEYDOWN message to check whether Esc is pressed since this message is not
generated if Esc key is hit when the dialog is displayed. This situation can be handled in the
following way:
Add a handler for the 'Cancel' button and add code to it as given below:
void CTrickDlg::OnCancel( )
{
short i = ::GetKeyState ( 27 ) ;
if ( i < 0 )
;
else
CDialog::OnCancel( ) ;
}
Here we have checked whether Esc is hit by calling ::GetKeyState( ) function and passing
to it virtual code of Esc key. If OnCancel( ) is called because of pressing Esc key do nothing
(note the ';' after if statement) otherwise call base class's OnCancel( ) to dismiss the
dialog.
How do I write code to change the color of every static text that gets displayed on
a dialog box?
Ans: Add a handler for WM_CTLCOLOR to the dialog class and add code to it as shown
below:
HBRUSH CMyDlg :: OnCtlColor ( CDC* pDC, CWnd* pWnd, UINT nCtlColor )
{
HBRUSH hbr = CDialog :: OnCtlColor ( pDC, pWnd, nCtlColor ) ;
SetTextColor ( pDC->GetSafeHdc( ), RGB ( 255, 255, 0 ) ) ;
return hbr ;
}
57
58
What are the series of actions that take place when I try to close a window?
Ans: When we try to close an application by clicking on the close button, a WM_CLOSE
message is sent to our application. If we do not handle this message then it is passed on to
the default window procedure. The default window procedure destroys the window by calling
the ::DestroyWindow( ) API function. This function places a WM_DESTROY message in the
message queue of our application. If we do not handle this message once again the default
window procedure gets a shot at it. Following WM_DESTROY, is another message called
WM_NCDESTROY. In reaction to this message a handler OnNcDestroy( ) gets called. This
handler calls another functionPostNcDestroy( ). It is in this function that the
::PostQuitMessage( ) function is called. This function places a message WM_QUIT in the
message queue. When this message is retrieved, the message loop is terminated. This
ultimately leads to termination of the application.
59
How do I write code to provide an auto complete utility for the combo box?
Ans: Follow the steps given below:
1. Create a dialog based application.
2. Add a combo box control to the dialog template and then add a control variable say
m_combo.
3. Add a variable flag of type BOOL.
4. Add a virtual function PreTranslateMessage( ) and write following code to it.
BOOL mydialog :: PreTranslateMessage ( MSG* pMsg )
{
// check if a keyboard key is pressed
if ( pMsg -> message == WM_KEYDOWN )
{
flag = TRUE ;
int v = ( int ) pMsg -> wParam ;
if ( v == VK_DELETE || v == VK_BACK )
flag = FALSE ;
}
return CDialog::PreTranslateMessage ( pMsg ) ;
}
5. Add a handler for CBN_EDITUPDATE event for the combo box. Enter code given
below to this handler.
void mydialog :: OnEditupdateCombo1( )
{
if ( !flag )
return ;
// get the text typed in combo box
CString str ;
m_combo.GetWindowText ( str ) ;
int l = str.GetLength( ) ;
// get the starting & ending character position
DWORD cursel = m_combo.GetEditSel( ) ;
WORD start = LOWORD ( cursel ) ;
WORD end = HIWORD ( cursel ) ;
// If matching string not found
if ( m_combo.SelectString ( -1, str ) == CB_ERR )
{
m_combo.SetWindowText ( str ) ;
if ( cursel != CB_ERR )
m_combo.SetEditSel ( start, end ) ;
}
// place the selected string in combobox
if ( end < l && cursel != CB_ERR )
m_combo.SetEditSel ( start, end ) ;
else
m_combo.SetEditSel ( l, -1 ) ;
}
The PreTranslateMessage( ) function translates the window messages before they are
dispatched to the TranslateMessage( ) and DispatchMessage( ) functions. In this
function we are checking whether or not a keyboard key is pressed. If the key pressed is
other than 'del' or 'backspace' key then we are setting flag to TRUE, otherwise FALSE.
60
Then in the OnEditupdateCombo1( ) function first we have retrieved the text typed in the
edit control of the combo box. Then we have searched for the occurrence of the string that
begins with the same set of characters typed in edit control of combo box. If the matching
string is found then the text gets displayed in the edit control.
If there are two edit controls in a dialog, and the focus is set on one of the edit
controls, then how do I write code so that on pressing enter key the focus gets
set on next edit control?
Ans: When we press enter key the OnOK( ) handler gets called, which in turn calls
EndDialog( ) that dismisses the dialog. To prevent this default behavior we will have to
override OnOK( ) as shown below:
void CEditDlg::OnOK( )
{
short i = ::GetKeyState ( 0x0D ) ; // Where 0x0D is a virtual key code for Enter key
if ( i < 0 )
{
CWnd *w = GetFocus( ) ;
if ( &m_edit1 == w )
// where m_edit1 and m_edit2 are control variables added for two
edit controls respectively
m_edit2.SetFocus( ) ;
else
{
if ( &m_edit2 == w )
m_edit1.SetFocus( ) ;
else
61
CDialog::OnOK( ) ;
}
}
else
CDialog::OnOK( ) ;
}
Here we have called GetKeyState( ) function to which we have passed the virtual key code
of enter key. This function checks if the specified key is down (i.e. pressed) or up. If the key
is pressed then we have extracted the address of control on which the focus is. We have
compared this address with the address of controls we have created and accordingly set
focus on the next control.
How do I access the functions of CChildView class through a button handler of that
dialog, which has been popped up on clicking a menu item?
Ans: Follow the steps given below:
1. Add following data member with access specifier as private to the dialog class.
CWnd *w ;
2. Add the statement given below to the constructor of the dialog class
mydialog :: mydialog ( CWnd* pParent /*=NULL*/)
: CDialog ( mydialog::IDD, pParent )
{
// AppWizard generated code
w = pParent ;
}
3. In the handler for the menu item add code given below:
void CChildView :: OnShowDialog( )
{
mydialog d ( this ) ;
d.DoModal( ) ;
}
Here, we have passed the address of view window (i.e. the address of the object of
CChildView class) to the constructor of the mydialog class. Then #include 'ChildView.h'
file to the '.cpp' file of dialog class. Now, we can access any public member function of view
class through pointer w as shown below:
void mydialog :: OnApply( )
{
( ( CChildView * ) w ) -> myfun( ) ;
}
62
OnFileNew( ) to start the application with an empty document. This is the phase when the
framework creates document, frame window, and view objects using the information stored
in the document template.
How do I write code to add list of directories/files for given path to the
combobox?
Ans: To add a list of files/directories to a combo box we can use CComboBox::Dir( )
function. This function takes 2 argumentsthe attribute and a string specifying the path of
the directory or combination of wildcard strings. The attribute can be a combination of
values like DDL_READWRITE, DDL_READONLY, DDL_DIRECTORY, DDL_DRIVES, etc. The
following code snippet shows how this function can be used to get a list of directories as well
as files for a specified path.
void CComboDlg::OnGetList( )
{
m_combo.Dir ( DDL_DIRECTORY, "C:\\Windows\\*.*" ) ;
m_combo.SetCurSel ( 1 ) ;
}
While a dialog box is displayed if we hit the Enter key, the dialog box gets dismissed. This is
because, by default, when Enter key is hit, OnOk( ) handler gets called. However, many
times we provide few edit boxes on a dialog for taking input from user and we want that
after entering data if user hits Enter key, input focus should move on to the next edit box
instead of dialog box getting dismissed.
For this, we must override the OnOK( ) handler as shown below:
void mydialog::OnOK( )
{
CWnd *p = GetFocus( ) ;
int id = p -> GetDlgCtrlID( ) ;
switch ( id )
{
case IDC_EDIT1:
( ( CEdit* ) GetDlgItem ( IDC_EDIT2 ) ) -> SetFous( ) ;
break ;
case IDC_EDIT2:
( ( CEdit* ) GetDlgItem ( IDC_EDIT3 ) ) -> SetFous( ) ;
break ;
case IDOK:
CDialog::OnOK( ) ;
}
}
When we press Enter key although OnOK( ) handler gets called, focus remains on the same
control on which it was before calling OnOK( ). Hence, in OnOK( ) we can obtain the
63
pointer to that control and through this pointer we can obtain its ID. We can check this ID
and shift the focus accordingly. If the focus is on the OK button itself, we have called base
class's OnOK( ) to dismiss the dialog.
How do I write code that maximizes an MDI child window whenever a new
document is opened/created?
Ans: When we click on maximize button of view window, it gets maximized and the
framework places the child windows Control menu in the frames menu bar so that the user
can restore or close the child window and adds the title of the child window to the framewindow title. To maximize the child window we need to call
CMDIChildWnd::MDIMaximize( ) function. This function must be called by the main
frame window. Add code given below to OnDraw( ) of view class.
#include "MainFrm.h"
void CMDIView :: OnDraw ( CDC* pDC )
{
//AppWizard generated code
if ( flag == 0 ) // where flag is data member of view class, initialized with zero
{
64
How do I add controls like combo box, button control, etc. to a toolbar and make it
dockable?
Ans: To have a toolbar containing controls like combo box, button, etc. we need to add a
dialog bar to our application. Follow the steps given below:
1. Create an SDI application.
2. Add a dialog bar as a new resource. Then add controls on this dialog bar.
3. Add a new class say mybar to manage this dialog bar.
4. Now add a data member say dlgbar of type CDialogBar to the CMainFrame class.
5. Open OnCreate( ) function and add following code to it.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// AppWizard generated code
dlgbar.Create ( this, IDD_DIALOGBAR, WS_CHILD | WS_VISIBLE | CBRS_TOP |
CBRS_GRIPPER | CBRS_TOOLTIPS |
CBRS_FLYBY | CBRS_SIZE_DYNAMIC, IDD_DIALOGBAR ) ;
dlgbar.EnableDocking ( CBRS_ALIGN_ANY ) ;
EnableDocking ( CBRS_ALIGN_ANY ) ;
DockControlBar ( &dlgbar ) ;
return 0 ;
}
6. Lastly, add functions to handle the events of the corresponding controls of the dialog bar,
to the CMainFrame class.
65
BOOL CMyAppApp::InitInstance( )
{
// AppWizard generated code
// Register the application's document templates.
// Document templates serve as the connection between documents, frame windows and
views.
CSingleDocTemplate* pDocTemplate ;
pDocTemplate = new CSingleDocTemplate ( IDR_MAINFRAME, RUNTIME_CLASS
( CMyAppDoc ),
RUNTIME_CLASS ( CMainFrame ), // main SDI frame window
RUNTIME_CLASS ( CMyAppView ) ) ;
AddDocTemplate ( pDocTemplate ) ;
// AppWizard generated code
return TRUE ;
}
To help an application support different types of documents a document template is created.
After the document template is created it should get added to the list of document
templates maintained by the application object. This job is done by AddDocTemplate( ).
Each template registered in this way defines one document type the application supports.
SDI supports only one document type whereas MDI supports multiple document types.
How do I write code that gives an IP address and the port on which the client
program is running?
Ans: While working with CSocket class many times an IP address or port number on which
the client program is running is required. We can obtain this information by using
CAsyncSocket::GetPeerName( ) function. Override CAsyncSocket::OnReceive( ) in the
class derived from CSocket and call the GetPeerName( ) function in it as shown below:
CString ipadr ;
UINT ip ;
GetPeerName ( ipadr, ip ) ;
CString str ;
str.Format ( "IP Address: %s and Port No.:%u", ipadr, ip ) ;
AfxMessageBox ( str ) ;
66
return TRUE ;
When we use the MCI functions it is necessary to link the file 'vfw32.lib' file to our project.
Also #include 'vfw.h' file to make these functions available.
If our application needs to take some action when the machine is about to shut down we
can do so in OnEndSession( ) handler. All the top-level windows receive WM_ENDSESSION
message when the session is about to close. Handle the WM_ENDSESSION message in
frame class as given below:
void CMainFrame::OnEndSession ( BOOL bEnding )
{
CFrameWnd::OnEndSession ( bEnding ) ;
MessageBox ( "The Windows is shuting down" ) ;
}
67
The function GetTextExtent( ) returns the dimension, i.e. width and height of the given
string with respect to the current font selected in the device context. Then we have checked
for the width of the list box by calling GetHorizontalExtent( ) function.
GetHorizontaExtent( ) function returns the width of the list box (in terms of pixels). If it
happens to be smaller than the size returned by GetTextExtent( ), then we are setting the
scrollable width of the list box to the one returned by GetTextExtent( ). Note that the list
box must have the style 'Horizontal Scroll' checked in order to enable the horizontal scroll
bar.
How do I write code that hides current dialog and displays a new dialog when a
button is pressed and on pressing a button of the new dialog it dismisses new
dialog and unhide the previous dialog?
Create a dialog based application. Add a button called 'Next' and add a handler for it. Add a
new dialog using Resource Editor. Add a class say Dialog1 to handle the newly added
dialog. Add a button called 'Previous' to new dialog and add a handler for it. Now add code
to OnNext( ) as shown below:
void CMyDlg :: OnNext( )
{
this -> ShowWindow ( SW_HIDE ) ;
Dialog1 dlg ( this ) ; // this is the address of parent dialog
dlg.DoModal( ) ;
}
Add a data member called m_parent of type CWnd* to Dialog1 class. Collect the address
of parent window in m_parent in the constructor as shown below:
Dialog1 :: Dialog1 ( CWnd* pParent /*=NULL*/ )
: CDialog ( Dialog1 :: IDD, pParent )
{
//AppWizard generated code
m_parent = pParent ;
}
Now, add code to OnPrevious( ) handler as shown below:
#include "MyDlg.h"
void Dialog1 :: OnPrevious( )
{
EndDialog ( 1 ) ; // to dismiss current dialog
( ( CMyDlg * ) m_parent ) -> ShowWindow ( SW_SHOW ) ; // to show previous dialog
}
68
How do I change the text of Open/Save button of the common dialog CFileDialog?
Ans: To change the text of button in CFileDialog, follow the steps given below.
1. Add a new class mydlg say for example, derived from CFileDialog to your
application.
2. Add message handler for WM_ONINITDIALOG to this class. Then enter code given
below to OnInitDialog( ) function.
BOOL mydlg :: OnInitDialog( )
{
CFileDialog::OnInitDialog( ) ;
CButton *b = ( CButton * ) GetParent( ) -> GetDlgItem ( IDOK ) ;
if ( b )
b -> SetWindowText ( "mybutton" ) ;
return TRUE ;
}
3. Create an object of mydlg class and pass necessary parameters to the constructor.
Call DoModal( ) to display the CFileDialog with the button 'mybutton' .
69
The standard Find dialog is a modeless dialog. Hence, we are required to allocate space for
object of CFindReplaceDialog on heap. The first parameter passed to Create( ) function,
indicates to display Find dialog. Passing FALSE would display standard Find/Replace dialog.
The next parameter specifies the string to search for. Since we don't want to replace the
found string, we have specified NULL at the place of third parameter. FR_DOWN is the
default value which specifies that the search has to be proceed in downward direction. On
clicking 'Find Next' button a handler should get called. To do so add a user-defined member
function say OnFind( ) to the dialog class. To be able to call the handler, we need to
register a message. Hence, add code shown below to the header file of dialog class.
static UINT WM_FIND = ::RegisterWindowMessage ( FINDMSGSTRING ) ;
Then add following entry in message map.
BEGIN_MESSAGE_MAP ( CMyDlg, CDialog )
//{{AFX_MSG_MAP(CFind_ReplaceDlg)
ON_REGISTERED_MESSAGE( WM_FIND, OnFind )
//}}AFX_MSG_MAP
END_MESSAGE_MAP( )
How do I move a dialog when I drag it by pressing left mouse button at any point?
Ans: When we press a left mouse button on the title-bar area of a window and drag it then
only the window gets moved. In order to get the dialog window moved when the left mouse
button is pressed at any other point in the dialog window, we need to add a message
handler for WM_NCHITTEST. The OnNcHitTest( ) handler gets called every time the mouse
is moved. It gets called for that window which contains the cursor or the window that has
called SetCapture( ) to capture the mouse input. The function takes the screen coordinates
of the cursor as a parameter and returns enumerated values for mouse. Enter code to this
handler as shown below:
UINT mydlgDlg::OnNcHitTest(CPoint point)
{
CRect r ;
GetClientRect ( &r ) ;
ClientToScreen ( &r ) ;
if ( r.PtInRect( point ) )
return HTCAPTION ;
return CDialog::OnNcHitTest ( point ) ;
}
Here we have checked whether the point lies within client area or not. If it is, then we are
returning an enumerated value HTCAPTION which indicates that mouse is hit in the title-bar
area of a window. As a result, the dialog box widow will get moved as we drag it by clicking
left mouse button.
70
Thus when a frame window is destroyed, the object associated with that window is
automatically deleted.
Functions preceded by 'Afx' prefix are global function which can be called anywhere.
If changes are made in resources then during compilation only the resources get
compiled and not the whole
program.
Selecting 'Use MFC in static DLL' from Project | Settings will create a stand alone
exe.
How do I write code that displays the flyby text for an item of a menu created
programmatically ?
Ans: To get the flyby text displayed on a status bar for an item of menu created
programmatically, handle WM_MENUSELECT message in your application as shown below:
void CMainFrame :: OnMenuSelect ( UINT nItemID, UINT nFlags, HMENU hSysMenu )
{
if ( nItemID == 300 ) // where 300 is an ID for an item of menu created programmatically
m_wndStatusBar.SetPaneText ( 0, "Draws a line" ) ;
else
CFrameWnd :: OnMenuSelect ( nItemID, nFlags, hSysMenu ) ;
}
71
Following code shows how to create a coordinate system where origin is at the center of the
client area and the size of one unit in x-direction is twice the size of one unit in y-direction.
CPaintDC d ( this ) ;
CRect r ;
GetClientRect ( &r ) ;
d.SetViewportOrg ( r.right / 2, r.bottom / 2 ) ;
d.SetMapMode ( MM_ANISOTROPIC ) ;
d.SetWindowExt ( 10, 20 ) ;
d.SetViewportExt ( r.right, r.bottom ) ;
d.Rectangle ( 0, 0, 2, 2 ) ;
How do I add a 'cancel' button to the message box dialog that gets displayed when
we call MessageBox( ) function?
Ans: The following code snippet demonstrates this:
void CChildView :: fun( )
{
MessageBox ( "Hello!", "Message", MB_OKCANCEL ) ;
}
The third parameter MB_OKCANCEL passed to the MessageBox( ) function adds two push
buttons OK and Cancel to the message box dialog. In addition to this we can also display
the icon in the message box by setting flag as MB_ICONSTOP, MB_ICONERROR,
MB_ICONHAND etc.
72
How do I get the list of logical drives in the system and add it in a combobox?
Ans: The API function GetLogicalDriveStrings( ) fills a buffer with strings that specify
valid logical drives in the system. The buffer is filled with the null terminated strings where
every string is the name of the logical drive. The following code demonstrates how we can
get the logical drives and add them in the combobox.
void CMydlgDlg::OnDrives( )
{
char buff[100] ;
DWORD str = GetLogicalDriveStrings ( sizeof ( buff ) / sizeof ( char ), buff ) ;
char *s = buff ;
while ( *s )
{
LPCTSTR dp = s ;
if ( *dp != '\\' )
m_combo.AddString ( dp ) ;
s += 2 ;
}
m_combo.SetCurSel ( 1 ) ;
}
The GetLogicalDriveStrings( ) function takes two parameters, first, the size or length of
the buffer in which the series of null terminated strings are to be stored and the second is a
pointer to the buffer that receives the strings.
73
If we create a list control dynamically then we cannot add handlers for it through
ClassWizard. If we need to add a handler then we have to add it manually. For example, if
we want to add double-click handler for a list control then we need to add following
declaration in the '.h' file:
void OnDblclkItem ( NMLISTVIEW *p, LRESULT *q ) ;
Also we need to add following entry in the message map.
ON_NOTIFY_REFLECT ( NM_DBLCLK, OnDblclkItem )
74
How do I write code that displays a progress control while copying contents?
Ans: Use SHFileOperation( ) function as shown below:
void MyDlgdlg::OnCopy( )
{
SHFILEOPSTRUCT s ;
::ZeroMemory ( &s, sizeof ( s ) ) ; // Initialize the structure
CString f = "C:\\MyFolder" ;
CString t = "D:\\" ;
char from [ MAX_PATH ], to [ MAX_PATH ] ; // buffer used to copy source and target path
strcpy ( from, f ) ;
int l = f.GetLength( ) ;
from[l+1] = '\0' ;
strcpy ( to, t ) ;
l = t.GetLength( ) ;
to[l+1] = '\0' ;
// Set the values in structure
s.hwnd = this -> m_hWnd ;
s.wFunc = FO_COPY ;
s.pFrom = ( LPCTSTR ) from ;
s.pTo = ( LPCTSTR ) to ;
s.fFlags = FOF_SIMPLEPROGRESS ;
s.lpszProgressTitle = "Copying files..." ;
::SHFileOperation ( &s ) ;
}
75