Friday, October 30, 2009

University Exam Paper OOPS using Visual C++

M. Sc. Sem. I (IT & CA) Examination
Jan-Feb 2009
P101 - OOPS Using Visual C++


Que- 1 Attempt any three of the following : [30 marks]

(1)Write an application to display the current cursor value of horizontal scrollbar in the title bar of the dialog box.
(2)Write an application by taking two buttons as following:
(a)User can create two dynamic edit box and static box by clicking first button.
(b)User can interchange the values of edit boxes by clicking the second button.
(3)What is OOP ? Explain encapsulation and polymorphism.
(4)Write an application to manipulate database using ODBC connectivity. User can perform Add, Edit, Delete, Previous, Last and First.

Que-2 Attempt any two : [10 marks]

(1)Prepare a project explaining the push button with enabling, disabling and hide-show utility.
(2)Write an application which can create the text file from one button and can open that created text file in notepad from second button.
(3)Explain the visual C++ development environment.

Que-3 Attempt any six : [30 marks]

(1)Write a VC++ project that draws a circle. And clicking within it changes the circle color.
(2)Write an application to display the text from edit box into the client area of dialog box whenever user presses the right mouse button.
(3)Explain the CArchieve and CFile class with suitable example.
(4)Explain MFC.
(5)Explain (a) GetDocument( ) (b) CPen
(6)What is CEdit ? Explain with example.
(7)Explain with example Move TO-line To.
(8)List the different extension used in VC++ project file. Explain any two of them.



Wednesday, October 28, 2009

Internal Exam Question Paper

P-101 : Object Oriented Programming Using Visual C++

[Time : 2 hours ] [Total Marks : 50]

Que-1 Do as Directed. (Any Ten) [10]

1. How many parameters needed while Overloading Binary Operator using Friend function?
2. Which function is used to get the text at particular position from a ComboBox?
3. Can we Create more than one Project in a single Workspace?
4. Which different views are contained in Workspace Window?
5. Can we Map the void OnOK() function with any event? Why?
6. In which type of Inheritance Virtual Class is needed?
7. Which function is used to clear all entries from a ListBox?
8. Write down syntax for Enable and Disable EditBox Control?
9. List out all Parameter Name Used in MessageBox () function?
10. What is full form of PCH Extension? What information it Contain?
11. Write Short-cut Keys for Build and Execute Program.
12. When fatal error C1083 occurs?

Que-2 Answer the following Questions.
1. Explain Function. (1) UpdateData ( ). (2) Invalidate ( ). (3 Marks)
2. Explain CEdit with example. (3 Marks)
3. Write a Code to Set Current Cursor Position on Title bar of Dialog box. Use appropriate Event (2 Marks)
4. Write a Code to calculate no. of Button clicks and show it using MessageBox. (With all Parameters) (2 Marks)

Que-3 Answer the following Questions. (Any Three) [15]
1. Write a Program to draw a Line using Mouse Move events.
2. Write a Program to Animate Rectangle.
3. Write a Program to Add min 5 numbers in ComboBox. When user press
the Calculate Button show Addition of Numbers in MessageBox.
4. Write a program to move values from one ListBox to another.
(One by One and All at Once).

Que-4 Answer the following Questions. (Any Three) [15]
1. List the different extension used in VC++. Explain any Two in brief.
2. List out different categories of Messages. Explain Message Map with Example.
3. What is OOP? Explain Inheritance and polymorphism.
4. Explain CPen and CBrush.

Saturday, October 24, 2009

VC++ Practical List



M.Sc (IT & CA) Sem – I

Object Oriented Programming using Visual C++

List of Practical

----------------------------------------------------------------------------------

(1)

Create Dialog based Application with command button and MessageBox () (Use all Parameters) to print the message with no of clicks whenever user clicks on command button.

(2)

Develop Calculator using Dialog.

Hint: 1 Edit Box, 4 Radio Buttons,

Error Message like Divide by 0 Error,

Use Appropriate Controls.
(3)

Create Dialog based Application as shown below with use of ListBox (3a) and ComboBox.(3b)

(4)

Create Dialog based Applications with two EditBox to show use of different String function and Show final answer in MessageBox.

Hint: 2 EditBox, Radio Buttons (Min 5), CheckBox (Min 5)

Create all Controls through Coding.
(5)

Create Dialog based Applications with multiple Dialog Box to Show functionality of ProgressBar and Slider.

Hint: 3 DialogBox ,

1-> Create and Send Message (Slider)

2-> Show the Status of Message (Progress Bar)

3-> Read Message

* If Possible Implement Vice-Versa and Use Animation.
(6)

Create Dialog based Application with Multiple Dialog box.


Create Dynamic Static Box in 1st Dialog with following values.

* Position where user press Left Button.

* Caption = Text in EditBox of 2nd Dialog Box.
(7)

Write a program to draw a line using three different mouse events.

Hint:

1-> LBUTTONDOWN

2-> LBUTTONUP

3-> MOUSEMOVE
(8)
Write a program to draw a circle, a polygon and a rectangle in the client area. Create your own pen and brush. Each shape should be drawn with different pen and brush.
(9)

Write a program to Animate Circle.

Hint:

* Circle should be Moved from one Point to Another.

* While Moving towards another Point its size should be Changed.

(10)

Write a program to Make Simple Text Editor.

Hint:

* Use Virtual Key.

* User Can Enter and Edit Text.

Submission Date : 15-Nov-2009

Saturday, October 10, 2009

The Document/View Approach



To create an application, you obviously should start by providing a frame. This can be taken care of by deriving a class from CFrameWnd. Here is an example:

class CMainFrame : public CFrameWnd
{
DECLARE_DYNCREATE(CMainFrame)

DECLARE_MESSAGE_MAP()
};

To give "physical" presence to the frame of an application, you can declare an OnCreate() method. Here is an example:

class CMainFrame : public CFrameWnd
{
DECLARE_DYNCREATE(CMainFrame)

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};

The easiest way you can implement this method is to call the parent class, CFrameWnd, to create the window. As we have seen in the past, if this method returns 0, the frame has been created. It returns -1, this indicates that the window has been destroyed. Therefore, you can create a frame as follows:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// Call the base class to create the window
if( CFrameWnd::OnCreate(lpCreateStruct) == 0)
return 0;

// else is implied
return -1;
}

To allow users to interact with your application, you should provide a document. To do this, you can derive a class from CDocument so you can take advantage of this class. If you do not plan to do anything with the document, you can just make it an empty class. Here is an example:

class CExerciseDoc : public CDocument
{
DECLARE_DYNCREATE(CExerciseDoc)

DECLARE_MESSAGE_MAP()
};

Besides the few things we have learned so far, your next big decision may consist on the type of application you want to create. This is provided as a view. The most fundamental class of the view implementations in the MFC is CView. Because CView is an abstract class, you cannot directly use it in your application. You have two main alternatives. You can derive your own class based on CView (the CView class itself is based on CWnd) or you can use one of the many view classes that the MFC provides. The classes that are readily available to you are:

Class Description
CEditView Used for a basic text editing application
CRichEditView Allows creating rich documents that perform text and paragraph formatting
CScrollView Provides the ability to scroll a view horizontally and vertically
CListView Provides a view that can display a list of items
CTreeView Allows displaying a list of items arranged as a tree
CFormView Used to create a view that resembles a dialog box but provides the document/view features
CDaoRecordView Provides a view that resembles a dialog box but used for database controls
CCtrlView Provides parental guidance to the CEditView, CListView, CTreeView, and CRichEditView

As we move on, we will study these classes as needed.

Once you have a frame, a document, and a view, you can create an application, which, as we have learned so far, is done by deriving a class from CWinApp and overriding the InitInstance() method. In the InitInstance() implementation, you must let the compiler know how a document is created in your application. To do this, you must provide a sample document, called a template, that defines the parts that constitute a document for your particular type of application. This is done using a pointer variable declared from CDocTemplate or one of its derived classes.

Thursday, October 8, 2009

Visual C++ Basic Knowledge



Controls Fundamentals


A Windows control, in this book called a control, is an object that displays or is part of an application and allows the user to interact with the computer. There are various types of controls as we will see in this book:

  • a text-based control is an object whose main function is to display to, or request text from, the user
  • A list-based control displays a list of items
  • A progress control is used to show the evolution of an action
  • a static control can be used to show colors, a picture or something that does not regularly fit in the above categories

To make your application as efficient as possible, you will add controls as you judge them necessary. Some and most controls are already available so you can simply customize their behavior and appearance. Sometimes you will need a control for a specific task or for a better look. If such a control is not available, you may have to create your own.

There are two main ways a control is made part of your application. At design time, which is referred to the time you are visually creating an application, you will select controls and place them on a host. Another technique, referred to as run time, consists of creating control programmatically. In this case you must write all the code that specifies the control's appearance and behavior.

The Parent-Child Window Relationship


There are two types of windows or controls you will deal with in your applications. The type is defined by the relationship a window has with regards to other windows that are part of an application:

  • Parent: a window is referred to as a parent when there are or there can be other windows that depend on it. For example, if you look at the toolbar of Visual C++, it is equipped with the buttons. The toolbar is a parent to the buttons.
    When a parent is created, it makes it possible to "give life" to other windows that can depend on it. The most regular parents you will use are forms and dialog boxes.
  • Child: A window is referred to as child when its existence and especially its visibility depend on another window called its parent. When a parent is created, made active, or made visible, it gives existence and visibility to its children. When a parent gets hidden, it also hides its children. If a parent moves, it moves with its children, the children keep their positions and dimensions inside the parent. When a parent is destroyed, it also destroys its children (sometimes it does not happen; a parent may make its children unavailable but they may still be occupying memory after the parent has been destroyed). Child controls depend on a parent because the parent "carries", "holds", or hosts them. All of the Windows controls you will use in your applications are child controls. A child window can also be a parent of another control. For example, the Standard toolbar of Visual Studio is the parent of the buttons on it. If you close or hide the toolbar, its children disappear. At the same time, the toolbar is a child of the application's frame. If you close the application, the toolbar disappears, along with its own children. In this example, the toolbar is a child of the frame but is a parent for its buttons.

Author Note

It is important to understand that this discussion refers to parents and children as windows, not as classes:

  • The CButton class is based on CWnd. Therefore, CWnd is the parent class of CButton
  • When a button is placed on a form, the form, which is based on CView (indirectly) is the window parent of the button and not its class parent

If you are creating an independent window, as we have done with the frames so far, you can simply call its Create method in its constructor and define its characteristics. Such a class or window is a prime candidate for parenthood.

Parent Controls


An object is referred to as a parent or container when its main job is to host other controls. This is done by adding controls to it. The most commonly used parent control is the dialog box. In the previous lesson, we learn how to easily create a dialog-based application and how to add a dialog box to an application.

Besides the WNDCLASS structure, the Win32 library also offers the WNDCLASEX structure used to create an application. Besides all of the characteristics of WNDCLASS, the WNDCLASSEX structure requires that you specify the size of the structure and it allows you to set a small icon for your application. This can be done as follows:

const char *WndName = "Windows Fundamentals";
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
 
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                  LPSTR lpCmdLine, int nCmdShow)
{
    MSG        Msg;
    WNDCLASSEX WndClsEx;
 
    WndClsEx.cbSize        = sizeof(WNDCLASSEX);
    WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
    WndClsEx.lpfnWndProc   = WndProc;
    WndClsEx.cbClsExtra    = 0;
    WndClsEx.cbWndExtra    = 0;
    WndClsEx.hInstance     = hInstance;
    WndClsEx.hIcon         = LoadIcon(NULL, IDI_ASTERISK);
    WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    WndClsEx.hbrBackground = (HBRUSH)COLOR_ACTIVECAPTION;
    WndClsEx.lpszMenuName  = NULL;
    WndClsEx.lpszClassName = ClsName;
    WndClsEx.hIconSm       = LoadIcon(NULL, IDI_ASTERISK);
 
    RegisterClassEx(&WndClsEx);
 
    while( GetMessage(&Msg, NULL, 0, 0) )
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
 
    return Msg.wParam;
}

Besides the CreateWindow() function, the Win32 library provides the CreateWindowEx() function you can use to create a window. The CreateWindowEx() function has the followsing syntax:

HWND CreateWindowEx(
  DWORD dwExStyle,
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle, 
  int x,
  int y, 
  int nWidth, 
  int nHeight, 
  HWND hWndParent, 
  HMENU hMenu,
  HINSTANCE hInstance,
  LPVOID lpParam
);

Parent Windows Styles


The role of a parent object is very important to the other controls it is hosting. Therefore the parent window must possess some valuable characteristics. For example, you must provide a way to close the parent window and/or to move it. This is usually done by the user dragging the title bar of a frame or a dialog box. If the parent is a toolbar, you can make it dockable, in which case it can be moved and positioned on various parts of the frame window. You can also allow the user to move a parent such as a dialog box by dragging its body. If you create the window using the CreateWindow() function and specify the style as WS_OVERLAPPEDWINDOW, the window would be equipped with a title that has all three system buttons and the system menu. The CreateWindowEx() function allows you to specify further features for a parent window.

Sunken Edges: A window appears with a sunken when its body is sunk with regards to its borders. To create such as window, applying the WS_EX_CLIENTEDGE style. To get this effect on a dialog box, while designing it, set its Client Edge to True.

Raised Edges: A window can have an inside body that appears to be raised with regards to its borders. Such a window can be created by adding the WS_EX_WINDOWEDGE style.

Overlapped Windows: A window is referred to as overlapped when it presents a combination of a sunk and a raised edge. Such a window can be created by either combining the WS_EX_CLIENTEDGE and the WS_EX_WINDOWEDGE styles or by using the WS_EX_OVERLAPPEDWINDOW. To get this effect of a dialog box, set its Style to Overlapped.

Tool Windows: A tool window is a parent object mostly used to float, like a toolbar, on a frame for another window. It has a short title bar that displays its caption. It cannot be mini or maximized but it can be equipped with the system menu:

To create a tool window, set or add the WS_EX_TOOLWINDOW extended style to the CreateWindowEx() function:

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                  LPSTR lpCmdLine, int nCmdShow)
{
    HWND               hWnd;
    MSG        Msg;
    WNDCLASSEX WndClsEx;
 
    . . .
 
    RegisterClassEx(&WndClsEx);
 
    hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, 
                      ClsName,
                         WndName,
                         WS_OVERLAPPEDWINDOW,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);
 
    return Msg.wParam;
}

The above tool window allows the user to resize it by dragging its borders or corners. If you do not want the user to be able to resize the tool window, set its style to WS_CAPTION and WS_SYSMENU:

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                  LPSTR lpCmdLine, int nCmdShow)
{
    HWND               hWnd;
    MSG        Msg;
    WNDCLASSEX WndClsEx;
 
    . . .
 
    RegisterClassEx(&WndClsEx);
 
    hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, 
                      ClsName,
                         WndName,
                         WS_CAPTION | WS_SYSMENU,
                         . . .,
                         );
}

If you are working on an MFC application and designing your dialog box, to make it a tool window, set the Tool Window property to True. If you want the user to be able to resize the window, set its Border property to Resizing. If you do not want the user to resize the window, set its Border property to Dialog Frame.

Windows Taskbar Button: By default, a tool window does not display display a button on the taskbar. If you are creating a window that will depend on a main window such as a frame, you should keep that default. If for any reason you want to display a button for the tool window, add the WS_EX_APPWINDOW extended style.

Window on Top: If you want your window to stay on top of another or other windows, you have two choices. If the window you are creating, such as a dialog box, is being added to a frame-based or a form-based application and you want that window to always be on top of its parent window, add the WS_VISIBLE style to it and display it using ShowWindow(SW_SHOW). For a dialog box you are designing, set its Visible property to True. If you want the window to always be on top of other windows, add the WS_EX_TOPWINDOW extended style to it.

Control Creation Options


To allow the user to interact with the computer, you equip your computer with the necessary controls. The controls are positioned on the client area of the parent window. The easiest technique used to add a control to your application consists of picking it up from the Controls toolbox and positioning it on the parent. To help with this, Visual C++ provides a series or ready-made objects on the Controls toolbox:


Visual C++ 6 Controls

Visual C++ 7 Controls


The second option used to add a control to an application consists of programmatically creating it. All visible controls of the MFC library are based on the CWnd class. This class is equipped with all the primary functionality that a regular window object needs. As the parent of all visible window classes, it provides the other controls with properties and methods to implement their appearance and behavior. To use the CWnd class:

  • You can directly derive a class from CWnd
  • You can use one of the CWnd-derived classes (CView, CFrameWnd, etc)
  • You can derive a class from one of the CWnd-derived classes; for example you can create a class based on CStatic
  • You can directly declare a CWnd variable in your application and initialize it the class of your choice

To create a control using a known class, you must declare a variable of the class on which the control is based. Every control is based on a specific class, and that class is directly or indirectly derived from CWnd. An example of such a declaration would be:

void CParentLoader::TodaysMainEvent()
{
        CStatic Label;
}

You can also declare the variable as a pointer. In this case, make sure that you initialize the class using the new operator. An example would:

void CParentLoader::TodaysMainEvent()
{
        CStatic *Label = new CStatic;
}

Based on the rules of inheritance and polymorphism, you can also declare the pointer as CWnd but initialize it with the desired class. Here is an example:

void CParentLoader::TodaysMainEvent()
{
        CWnd *Panel = new CStatic;
}

You can also use the CWnd::Create() method to create a control. The syntax of this method is:

virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                 DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
                 UINT nID, CCreateContext* pContext = NULL);

To create a fancier control, you can use the CWnd::CreateEx() method.

The availability of a child window to other parts of a program is defined by the scope in which the control is created. If you create a control in an event or a method of a parent class, it can be accessed only inside of that event. Trying to access it outside would produce an error. If you want to access a child or dependent window from more than one event or method, you must create it globally. This is usually done by declaring the variable or pointer in the class of the parent.

After declaring the variable, to initialize it, call its Create() method. The syntax of this method depends on the window you are trying to create. After initializing the window, it may become alive, depending on the style or properties you assigned to it.

The other technique you can use is to derive a class from the control whose behavior and appearance can serve as a foundation for your control. For example, you can derive a control as follows:

class CColoredLabel : public CStatic
{
public:
        CColoredLabel();
        virtual ~CColoredLabel();
 
        DECLARE_MESSAGE_MAP()
};

Such a class as the above CColoredLabel gives you access to the public and protected properties and methods of the base class. To use the new class in your application, declare a variable from and call the Create() method.

The Control's Class Name


If you are programmatically creating a control, you must specify its name. To do this, you have various options.

Visual C++ ships with already defined names of classes you can use to create a control. These classes are:



Class Name

Why Use It?


STATIC

A static control can be used to display text, a drawing, or a picture


EDIT

As it name suggests, an edit control is used to display text to the user, to request text from the user, or both


RichEdit

Like an edit box, a rich edit control displays text, request it, or does both. Besides all the capabilities of the edit control, this control can display formatted text with characters or words that use different colors or weight. The paragraphs can also be individually aligned.
The RichEdit class name is used to create a rich edit control using the features of Release 1.0 of its class


RICHEDIT_CLASS

This control is used for the same reason as for the RichEdit class name except that it provides a few more text and paragraph formatting features based on Release 2.0


LISTBOX

A list box is a control that displays of items such as text arranged so each item, considered individually displays on its own line


COMBOBOX

A combo box is a combination of an edit control and a list box. It holds a list of item so the current selection displays in the edit part of the control


SCROLLBAR

A scroll bar is a rectangular object equipped with a bar terminated by an arrow of each end. It is used to navigate left and right or up and down on a document


BUTTON

A button is an object that the user clicks to initiate an action


MDICLIENT

This class name is used to create a child window frame for an MDI application

To use one of these classes, pass its name as string to the lpszClassName of the Create() or the CreateEx() methods. Here is an example that would create an edit box:

void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Memo = new CWnd;
 
        Memo->Create("EDIT", );
}

The second option you have is to either declare a WNDCLASS variable and initialize it, or call the AfxRegisterWndClass() function and pass it the desired values. As we saw in the previous lesson, this function returns a string. You can pass that string to the CWnd::Create() method as the class name. Here is an example:

void CSecondDlg::OnFirstControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *First = new CWnd;
        CString StrClsName = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, LoadCursor(NULL, IDC_CROSS),
                                          (HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(NULL, IDI_WARNING));
 
        First->Create(StrClsName, );
}

The other option you have is to specify the class name as NULL. In this case, the compiler would use a default name:

void CSecondDlg::OnSecondControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Second = new CWnd;
 
        Second->Create(NULL, );
}

The Control's Window Name


The window name is a default string that displays on the control when the control comes up. In the previous lessons, we saw that this string displays as caption on the title bar of a window frame or a dialog box. This property is different for different controls.

When designing a static control using the Static Text button , to set the window name, change the text of the Caption field.

To set the default text of a control, you can either do this when creating the control or change its text at any time. Again, this can depend on the control. To set the default text when programmatically creating the control, pass a string value as the lpszWindowName argument of the Create() or CreateEx() method. Here is an example:

void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Memo = new CWnd;
 
        Memo->Create("EDIT", "Voice Recorder", );
}

Many (even most) controls do not use a window name. Therefore, you can pass it as NULL

Introduction to Controls Styles and Common Properties


A style is a characteristic that defines the appearance and can set the behavior of a control. The styles are varied from one control to another although they share some of the characteristics common to most Windows controls.

After placing the control on the host, if you are using MSVC 6, you can right click the control and click Properties. This would display the Properties window that allows you to visually set the characteristics of the control. Some of the styles are available from the General tab and some others can be accessed from the Styles tab:

In Visual C++ 7, the Properties window displays, by default, to the lower right side of the IDE.

Childhood


All of the controls you will create need to be hosted by another control. During design, once you position a control on a dialog box or a form, it automatically gets the status of child. If you are programmatically creating your control, to specify that it is a child, add the WS_CHILD to the dwStyle argument. Here are examples:

void CSecondDlg::OnFirstControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *First = new CWnd;
        CString StrClsName = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW, LoadCursor(NULL, IDC_CROSS),
        (                                        HBRUSH)GetStockObject(BLACK_BRUSH),
                                                 LoadIcon(NULL, IDI_WARNING));
 
        First->Create(StrClsName, NULL, WS_CHILD, );
}
 
void CSecondDlg::OnSecondControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Second = new CWnd;
 
        Second->Create(NULL, NULL, WS_CHILD, );
}
 
void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Memo = new CWnd;
 
        Memo->Create("EDIT", "Voice Recorder", WS_CHILD, );
}
 
void CSecondDlg::OnFourthControl() 
{
        // TODO: Add your control notification handler code here
        CStatic *Label = new CStatic;
 
        Label->Create("United Nations", WS_CHILD, );
}

Visibility


If you want to display a control to the user when the parent window comes up, at design time, set the Visible property to True. If you are programmatically creating the control, add the WS_VISIBLE property. Here is an example:

void CSecondDlg::OnSecondControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Second = new CWnd;
 
        Second->Create(NULL, NULL, WS_CHILD | WS_VISIBLE, );
}

If you do not set the Visible property to True or do not add the WS_VISIBLE property, the control would be hidden (but possibly available) when its parent window comes up. Later on, you can display the control by calling the CWnd::ShowWindow() method. Remember that this method is used to either hide or to reveal a control by passing the appropriate constant, SW_HIDE to hide and SW_SHOW to display it. Here is an example that displays a control that missed the WS_VISIBLE property when it was created:

void CSecondDlg::OnFirstControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *First = new CWnd;
        CString StrClsName = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,
                                             LoadCursor(NULL, IDC_CROSS),
                                      (HBRUSH)GetStockObject(BLACK_BRUSH),
                                      LoadIcon(NULL, IDI_WARNING));
 
        First->Create(StrClsName, NULL, WS_CHILD);
        First->ShowWindow(SW_SHOW);
}

When the ShowWindow() method is called with the SW_SHOW value, if the control was hidden, it would become visible; if the control was already visible, nothing would happen. In the same way, when this method is called with the SW_HIDE argument, the control would be hidden, whether it was already hidden or not. If you want to check the visibility of a control before calling this method, you can call the CWnd::IsWindowVisible() method. Its syntax is:

BOOL IsWindowVisible() const;

This method returns TRUE if the control that called it is already visible. If the control is hidden, the method returns FALSE.

Availability


By default, after a control has been created, it is available to the user. If it is a non-static control, the user can possibly change select or change its value. If you do not want the control to be immediately usable but do not want to hide it, you can disable it. If you are designing the control, set its Disable property to True or checked. If you are programmatically creating the control, add the WS_DISABLED style as follows:

void CSecondDlg::OnSecondControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Second = new CWnd;
 
        Second->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED, );
}

When a control is disabled, the user can see it but cannot change its value. If for any reason a control is disabled, to enable it, you can call the CWnd::EnableWindow() method. In fact, the EnableWindow() method is used either to enable or to disable a window. Its syntax is:

BOOL EnableWindow(BOOL bEnable = TRUE);

Here is an example that disables a control called Memo:

void CSecondDlg::OnDisableMemo() 
{
        // TODO: Add your control notification handler code here
        Memo->EnableWindow(FALSE);
}

When calling the the EnableWindow() method, if you pass the TRUE value, the control is disabled, whether it was already disabled or not. If you pass the FALSE constant, it gets enabled, even it was already enabled. Sometimes you may want to check first whether the control is already enabled or disabled. This can be accomplished by calling the CWnd::IsWindowEnabled(). Its syntax is:

BOOL IsWindowEnabled( ) const;

This method checks the control that called it. If the control is enabled, the member function returns TRUE. If the control is disabled, this method returns FALSE. Here is an example:

void CSecondDlg::OnDisableMemo() 
{
        // TODO: Add your control notification handler code here
        if( Memo->IsWindowEnabled() == TRUE )
               Memo->EnableWindow(FALSE);
        else // if( !Memo->IsWindowEnabled() )
               Memo->EnableWindow();
}

Here is a simplified version of the above code:

void CSecondDlg::OnDisableMemo() 
{
        // TODO: Add your control notification handler code here
 
        Memo->EnableWindow(!Memo->IsWindowEnabled());
}

Borders


One of the visible features you can give a control is to draw its borders. Fortunately, most Microsoft Windows controls have a 3-D look by default. Some other controls must explicitly be given a border. To add a border to a control, at design time, set its Border property to True. If you are programmatically creating the control, add the WS_BORDER style to it:

void CSecondDlg::OnSecondControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Second = new CWnd;
 
        Second->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, );
}

To raised the borders of such a control, add the WS_THICKFRAME to its styles:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CtrlBorders->Create(NULL, NULL,
        WS_CHILD | WS_VISIBLE | WS_THICKFRAME, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Tab Sequence


When using the controls of a dialog, the user may choose to press Tab to navigate from one control to another. This process follows a sequence of controls that can receive input in an incremental order. To include a control in this sequence, at design time, set its Tab Stop property to True.

If you are creating your control with code, to make sure that it can fit in the tab sequence, add the WS_TABTOP. Here is an example:

void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
 
        Memo->Create("EDIT", "Voice Recorder",
                 WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, );
 
        CWnd *CanTab = new CWnd;
 
        CanTab->Create("BUTTON", "&Apply", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, );
}

Introduction to Extended Styles


Besides the above regular styles and properties used on controls, if you to add a more features to a window, you can create it using the CWnd::CreateEx() method. It comes in two versions as follows:

BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
              DWORD dwStyle, int x, int y, int nWidth, int nHeight,
              HWND hwndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL );
BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
              DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
              UINT nID, LPVOID lpParam = NULL);

In Visual C++ 6, some of the extended styles are on the Styles tab of the Properties window and some others are in the Extended Styles tab:

In Visual C++ 7, all styles are listed in the Properties window's vertical list:

Left Text Alignment


Text-based controls (such as the static label, the edit box, or the rich edit control) align their text to the left by default. This means that the control displays, its text starts on the left side of its area. To align text to the left on a control that allows it, at design time, select the Left value in the Align Text combo box.

The default text alignment of a text-based control is to the left. This is because the WS_EX_LEFT extended style is applied to it. If you want to reinforce this, you can add that style as the dwExStyle argument of the CreateEx() method. This can be done as follows:

void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
 
        Memo->CreateEx(WS_EX_LEFT, "EDIT", "Voice Recorder",
                 WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, );
}

Right Text Alignment


Many text-based controls, including the button, allow you to set their text close to the right border of their confined rectangle. To do this at design time, select the Right value in the Align Text combo box.

If you are programmatically creating the control, to align its text to the right, set or add the WS_EX_RIGHT extended style. Here is an example:

void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *CanTab = new CWnd;
 
        CanTab->CreateEx(WS_EX_RIGHT, "BUTTON", "&Apply",
                     WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, );
}

Extended Borders


Besides the border features of the dwStyle argument of the Create() member function, the CreateEx() method provides other border drawings to apply to a control.

Static Borders: To give a 3-D appearance to a control, especially one that does not receive input from the user (such as a static control), you can apply a static edge to it. To do this, at design time, set the Static Edge property to True. At run time, you can set or add the WS_EX_STATICEDGE extended style. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* Panel = new CStatic;
        
        Panel->CreateEx(WS_EX_STATICEDGE, "STATIC", NULL,
                         WS_CHILD | WS_VISIBLE, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Sunken Borders: You can further sink the borders of a control, give them an advanced 3-D appearance. To apply this effect at design time, set the Client Edge property to True. If you are programmatically creating a control, add the WS_EX_CLIENTEDGE extended style. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* Panel = new CStatic;
        
        Panel->CreateEx(WS_EX_CLIENTEDGE, "STATIC", NULL,
                         WS_CHILD | WS_VISIBLE, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Raised Borders: A control appears raised when it borders come out of the client area. This creates the effect of light left and top borders while the right and bottom borders appear darker. To apply this property, at design time, set the Modal Frame property to True or, at run time, add the WS_EX_DLGMODALFRAME extended style. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* Panel = new CStatic;
        
        Panel->CreateEx(WS_EX_DLGMODALFRAME, "STATIC", NULL,
                         WS_CHILD | WS_VISIBLE, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

To raise only the borders of a control without including the body of the control, you can combine WS_EX_CLIENTEDGE and the WS_EX_DLGMODALFRAME extended styles. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* Panel = new CStatic;
        
        Panel->CreateEx(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME,
                        "STATIC", NULL,
                         WS_CHILD | WS_VISIBLE, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Ownership and Identification: Parent Windows Logistics


One of the main roles of a parent window is its ability to host other controls. Such controls are called its children because the parent carries them when it is moved and it controls their availability. These controls are also called its clients because they request the parental service from it.

As mentioned already, at design time, you can pick up a control from the Controls toolbox and position it on the parent window. The child controls are added in an area referred to as the body of the parent window. The body of a window is a rectangular shape also called the client area:

A control can be added only in the client area and cannot exceed that area. To find out how much room a parent window is making available to its children, that is, to get the dimensions (and screen location) of the client area, you can call the CWnd::GetClientRect() function. Its syntax is:

void GetClientRect(LPRECT lpRect) const;

This function takes as argument a RECT or CRect variable and stores the location and dimension of the client rectangular area in it. In the following example, the GetClientRect() function is called to get the dimensions of the client area of a dialog box and use the resulting rectangular to paint that area:

void CSecondDlg::OnPaint() 
{
        CPaintDC dc(this); // device context for painting
        
        // TODO: Add your message handler code here
        CRect Recto;
        CBrush BlueBrush(RGB(0, 128, 255));
        CPen   BluePen(PS_SOLID, 1, RGB(0, 128, 255));
 
        GetClientRect(&Recto);
 
        CPen *OldPen = dc.SelectObject(&BluePen);
        CBrush *OldBrush = dc.SelectObject(&BlueBrush);
 
        dc.Rectangle(Recto);
 
        dc.SelectObject(OldBrush);
        dc.SelectObject(OldPen);
        // Do not call CDialog::OnPaint() for painting messages
}

To manage the area available to the control you are adding at design time, Visual C++ presents two options. If you display the grids, which is done by clicking the Toggle Grid button , the control can be positioned and resized anywhere in the area inside the borders of the parent window, as seen on the above red rectangle. No control can be positioned outside of the client area.

If you hide the grids, which is done by clicking the Toggle Guides button , a (blue dotted) rectangle appears in the client area:

This (blue dotted) rectangle allows you to effectively control the area available to your controls. To set the location and dimensions of the available area, click one of the (blue dotted) rectangle borders or corners and drag in the desired direction. If a control is positioned on a border that is moving, the control would be repositioned accordingly:

After setting the (blue dotted) rectangular location and area, you can add but cannot move a control outside of that (blue dotted) rectangle. The idea is to allow you to design a control or a group of controls in a (temporary) confined area. The (blue dotted) rectangle provides an effective means of aligning controls. After using it, if you want to add and manipulate controls outside of it, you should display the grids.

As mentioned already, the controls are confined to the client area offered by the parent window. After visually adding a control to a parent window, it assumes a location and takes some dimensions in the client area. The origin of the rectangular client area is on the upper-left corner of the parent window. The horizontal measurements move from the origin to the right. The vertical measurements move from the origin to the bottom:

At design time, to set the location and dimension of a control, after placing it on the parent, click and hold your mouse on the control, then drag left, top, right, and down. While doing that, refer to the right section of the status bar for the current location and dimensions of the control:

While moving and resizing the control, if you need help with this exercise, click the Toggle Grid button . When the grids are displaying, the control can only be located on grid indicators and when resizing the control, it can only fit on grid indicators. If you want to be more precise and ignore the grids, you have various options:

  • If you want to keep the grids but modify their distances, open the Guide Settings dialog box available from the Layout (MSVC 6) or Format (MSVC 7) menu then modify the Width and/or Height values in the Grid Spacing section:

  • If you want to keep the grids, press and hold Alt while you are dragging. While alt is down, you can position and dimension the control anyhow regardless of the grids settings, as long as you stay confined to the client area
  • You can hide the grids by clicking the Toggle Guides button . When this button is down, a control can moved and dimensioned anyhow as long as it stays within the confinements of the (blue dotted) rectangle
  • To use neither the grids nor the rectangular guide, click the button that is down to remove it.
    Whether the grids or the rectangular guide are displaying, to position a control with more precision, click it to select, then press one of the arrow keys to move the control by one pixel

If you are programmatically creating the control, to set its location, if you are using the first version of the CreateEx() method, specify the x value for the distance from the left border of the client area to the left border of the control, and pass the desired y value for the upper distance from the top border of the client area to the top border of the control. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* Panel = new CStatic;
        
        Panel->CreateEx(NULL, "STATIC", NULL,
                    WS_CHILD | WS_VISIBLE | WS_BORDER,
                    32, 15, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

If you specify negative values for the left and top distances, either the left or the top borders, respectively, will be hidden.

To set the dimensions of the control, if you are using the first version of the CreateEx() member function, specify the nWidth and the width and the nHeight for the height of the control. If you specify measures that are higher than the width of the client area - x or the height of the client area - y, the right border or the bottom border, respectively, of the control will be hidden.

To specify the location and the dimensions of the control at the same time, pass a RECT or a CRect variable as the rect argument of the Create() or the second version of the CreateEx() methods. Here are examples:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* btnApply = new CWnd;
        RECT Recto = {12, 16, 128, 64};
        btnApply->Create("BUTTON", "&Apply", WS_CHILD | WS_VISIBLE,
                     Recto, );
 
        CWnd *btnDismiss = new CWnd;
        btnDismiss->Create("BUTTON", "&Dismiss", WS_CHILD | WS_VISIBLE,
                       CRect(12, 68, 128, 120), );
 
        CWnd* Panel = new CStatic;
        Panel->CreateEx(WS_EX_DLGMODALFRAME, "STATIC", NULL,
                    WS_CHILD | WS_VISIBLE | WS_BORDER,
                    132, 16, 220, 120, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

It is important to understand that there is a tremendous difference on the way the dimensions of a control are calculated. Although we have not mentioned it, and we will not spend time on it because we are not going to treat controls differently, Common Controls are objects that started to be released with Windows 95. They calculate their width from the left border of the control to the right and the height of the control is calculated from the top border of the control down. Other (earlier) controls calculate their width by subtracting the specified nWidth value from the x value. This means that the nWidth starts on the left border of the client area. Based on this, for example if you are creating a button (class name = "BUTTON"), if you provide a value that <= x, the control would not be displayed because its width would be either nil or negative. Observe the following code:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* btnApply = new CWnd;
        RECT Recto = {12, 16, 12, 64};
        btnApply->Create("BUTTON", "&Apply", WS_CHILD | WS_VISIBLE,
                     Recto, );
 
        CWnd* Panel = new CStatic;
        Panel->CreateEx(WS_EX_DLGMODALFRAME, "STATIC", NULL,
                    WS_CHILD | WS_VISIBLE | WS_BORDER,
                    132, 16, 132, 120, );
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

The x and nWidth values of the button have the same value. In the same way, the x and the nWidth values of the panel object have the same value. When this program is executed, the button would not display because its width = 0. The panel object would display with a width of 132.

Once the control is already positioned on the client area, to get its location and dimensions, you can call the CWnd::GetWindowRect() method. Here is an example:

void CClientAreaDlg::OnBtnCalculate() 
{
        // TODO: Add your control notification handler code here
        CRect Recto;
        char LocDim[80];
        
        m_Rectangle.GetWindowRect(&Recto);
 
        sprintf(LocDim, "Left: %d, Top: %d, Width: %d, Height: %d",
                Recto.left, Recto.top, Recto.Width(), Recto.Height());
 
        SetWindowText(LocDim);
}

The Control Location and its Origin


When calling either the GetClientRect() or the GetWindowRect() methods to get the location and the dimensions of a control or another object, it is important to know the origin of the produced rectangle. By default, the rectangle returned by the GetWindowRect() method called by a control has its origin on the top left corner of the monitor and not on the top-left corner of the parent window. Consider the following button event. It gets the location and dimensions of a static control and stores them in a CRect variable. Then it paints a rectangle (it is supposed to paint the static control) located on, and equal to the dimensions, of the static control. Finally, it displays the properties of the rectangle that holds a static control:

void CClientAreaDlg::OnBtnCalculate() 
{
        // TODO: Add your control notification handler code here
        CRect Recto;
        char LocDim[80];
        
        m_Rectangle.GetWindowRect(&Recto);
 
        CClientDC dc(this);
        CBrush BlueBrush(RGB(0, 128, 192));
 
        dc.SelectObject(&BlueBrush);
        dc.Rectangle(Recto);
 
        sprintf(LocDim, "Left: %d, Top: %d, Width: %d, Height: %d",
                      Recto.left, Recto.top, Recto.Width(), Recto.Height());
 
        SetWindowText(LocDim);
}

After executing the program and moving the dialog box somewhere to the middle center of the screen and clicking the button, the result is as follows:

After moving the dialog box close to the top-left section of the screen and clicking the button again, the result is the following:

This clearly demonstrates that, although the static control is a child of the dialog box, the rectangle returned by the GetWindowRect() method is based on the screen and not the client area of the parent window. This is not an anomaly. It is purposely done so you can specify what origin you want to consider.

As seen in previous lessons, the origin of the screen is positioned on the top-left corner of the monitor. The origin of a client area is placed on its top-left corner. For example, the origin used by the above GetWindowRect() method is based on the screen. If you want the rectangle resulting from a call to either the GetClientRect() or the GetWindowRect() methods to be based on the client area of the control that called it, you can transfer the origin from the screen to the client. This is conveniently done with a simple call to the CWnd::ClientToScreen() method. It is overloaded as follows:

void ClientToScreen(LPPOINT lpPoint) const;
void ClientToScreen(LPRECT lpRect) const;

If the location you had requested is a point, pass its POINT or CPoint variable to the ClientToScreen() method. If the value you requested is a rectangle, pass its RECT or CRect variable. Here is an example:

void CClientAreaDlg::OnBtnCalculate() 
{
        // TODO: Add your control notification handler code here
        CRect Recto;
        char LocDim[80];
        
        m_Rectangle.GetWindowRect(&Recto);
 
        CClientDC dc(this);
        CBrush BlueBrush(RGB(0, 128, 192));
 
        ScreenToClient(Recto);
 
        dc.SelectObject(&BlueBrush);
        dc.Rectangle(Recto);
 
        sprintf(LocDim, "Left: %d, Top: %d, Width: %d, Height: %d",
                Recto.left, Recto.top, Recto.Width(), Recto.Height());
 
        SetWindowText(LocDim);
}

This time, even if the dialog box moves, the GetWindowRect() method returns the same rectangle.

If the location and/or dimension are given in client coordinates, to convert them to screen coordinates, call the ScreenToClient() method. It is overloaded as follows:

void ScreenToClient(LPPOINT lpPoint) const;
void ScreenToClient(LPRECT lpRect) const;

Parenthood


After specifying that the control you are creating is a child, which is done by placing the control on a form or a dialog box or by using or adding the WS_CHILD style, you must specify what window is the parent of your control. The parent of a control is automatically set when the control is placed on a host: the host becomes the parent.

If you are programmatically creating the control, you can specify its parent by passing a window handle as the pParentWnd argument of the Create() or or the second version of the CreateEx() member functions. If you are creating the control in a member function or an event of the parent window that is a descendent of CWnd, you can pass this argument as the this pointer. Here is an example:

void CSecondDlg::OnFirstControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *First = new CWnd;
        CString StrClsName = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,
                                                  LoadCursor(NULL, IDC_CROSS),
                                                  (HBRUSH)GetStockObject(BLACK_BRUSH)
                                                  LoadIcon(NULL, IDI_WARNING));
 
        First->Create(StrClsName, NULL,WS_CHILD | WS_VISIBLE | WS_BORDER,
                      CRect(20, 20, 120, 60), this, );
}

Specifying the parent as the this pointer indicates that when the parent is destroyed, it will also make sure the child control is destroyed. If you want the application to be the parent and owner of the control, use the first version of the CreateEx() method and pass the handle of your application as the hwndParent argument. Here is an example:

BOOL CClientAreaDlg::OnInitDialog()
{
        CDialog::OnInitDialog();
 
        SetIcon(m_hIcon, TRUE);        // Set big icon
        SetIcon(m_hIcon, FALSE);       // Set small icon
        
        // TODO: Add extra initialization here
        
        CWnd* stcLogo = new CWnd;
 
        stcLogo->CreateEx(WS_EX_DLGMODALFRAME, "STATIC", NULL,
                        WS_CHILD | WS_VISIBLE | WS_BORDER,
                           240, 90, 90, 40, this->m_hWnd, );
 
        return TRUE;  // return TRUE  unless you set the focus to a control
}

If, during the lifetime of your program you want to change a control's parent, you can call the CWnd::SetParent() method. Its syntax is:

CWnd* SetParent(CWnd* pWndNewParent);

Here is a rough example:

class CSecondDlg : public CDialog
{
// Construction
public:
        CSecondDlg(CWnd* pParent = NULL);   // standard constructor
 
        . . .
 
private:
        CWnd *lblFirstName;
        CWnd *AnotherParent;
};
CSecondDlg::CSecondDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CSecondDlg::IDD, pParent)
{
        //{{AFX_DATA_INIT(CSecondDlg)
               // NOTE: the ClassWizard will add member initialization here
        //}}AFX_DATA_INIT
        lblFirstName = new CWnd;
        AnotherParent = new CWnd;
}
void CSecondDlg::OnThirdControl() 
{
        // TODO: Add your control notification handler code here
        CWnd *Memo = new CWnd;
 
        Memo->Create("EDIT", "Voice Recorder",
                     WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
                     ES_MULTILINE | ES_WANTRETURN,
                     CRect(20, 80, 185, 224), this, );
        Memo->SetParent(AnotherParent);
}

To find out what window is the parent of a certain control, call the CWnd::GetParent() method. Its syntax is:

CWnd* GetParent() const;

This method returns a pointer to the parent of the control.

Control Identification


After adding a control to your your application, you must identify it. An identifier is not a string, it is a constant integer that is used to identify a control. Therefore, it is not the name of the control.

If you have just added the control, Visual C++ would assign a default identifier. If the control is static, it would have the IDC_STATIC identifier. Every other control gets an identifier that mimics its class name followed by a number. An example would be IDC_EDIT1. If you add another control of the same kind, it would receive an identifier with an incremental number. To have a better idea of each control, you should change their IDs to make them more intuitive. To do this, if you are visually adding the control, first display the Properties window:

The identifier can be a word or a hexadecimal number. Here are the rules you must follow when assigning identifiers:

It you decide to use a word

If you decide to use a hexadecimal number

  • The identifier must start with an underscore or a letter
  • The identifier must be in one word
  • After the first character, the identifier can have letters, underscores, and digits in any combination
  • The identifier must not have non-alphanumeric characters
  • The identifier cannot have space(s)
  • The identifier must start with a digit or one of the following letters: a, b, c, d, e, f, A, B, C, D, E, or F
  • The identifier can have only digits and the above letters except this: if the identifier starts with 0, the second character can be x or X followed by the above letters and digits so that, when converted to decimal, it must have a value between -32768 and 65535

Here are suggestions you should follow:

  • The identifier should be in all uppercase
  • The identifier should have a maximum of 30 characters
  • If the object is a form or dialog box, its identifier should start with IDD_ followed by a valid name. Examples: IDD_EMPLOYEES or IDD_EMPL_RECORS
  • If you are creating a control, the identifier should start with IDC_ followed by a name. Examples: IDC_ADDRESS or IDC_FIRST_NAME
  • If you are creating a static control but plans to use it in your code, (you must) change its identifier to something more meaningful. If the static control will hold text and you plan to change that text, you can identify it with IDC_LABEL. For a static control used to display a picture of employees, you can identify it as IDC_EMPL_PICTURE

The identifiers of the controls used in your application must be listed in a header file called Resource.h

If you visually add controls to your application, their identifiers are automatically added to this file. Even if you change the identifier of the control, Visual C++ updates this file. You can also manually add identifiers to this file, provided you know why you are doing that.

If you are programmatically creating a control, you can locally set an identifier by specifying a (randomly selected) decimal or hexadecimal number as the nID argument of the Create() or the second version of the CreateEx() methods. Here are examples:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd* btnApply = new CWnd;
        RECT Recto = {12, 16, 128, 64};
        btnApply->Create("BUTTON", "&Apply", WS_CHILD | WS_VISIBLE,
                     Recto, this, 0x10);
 
        CWnd *btnDismiss = new CWnd;
        btnDismiss->Create("BUTTON", "&Dismiss", WS_CHILD | WS_VISIBLE,
                       CRect(12, 68, 128, 120), this, 258);
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Alternatively, you can first create an identifier in the String Table. We saw how to do this in Lesson 3. You can also create an identifier using the Resource Symbols dialog box. Then use that identifier for your control. Here is an example:

BOOL CBordersDlg::OnInitDialog() 
{
        CDialog::OnInitDialog();
        
        // TODO: Add extra initialization here
        CWnd *btnDismiss = new CWnd;
        btnDismiss->Create("BUTTON", "&Dismiss", WS_CHILD | WS_VISIBLE,
                       CRect(12, 68, 128, 120), this, IDN_DISMISS);
 
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Control Functionality: Variables


There are two main ways you can refer to a control in your code. The first technique consists of using its identifier. This can help you find out what type of control the identifier refers to. In this case, you usually must cast the result to the right control's class. There are two prerequisites. First, you must know the ID or nID of the control you want to refer to. Then, you can call the CWnd::GetGldItem() method. It comes in two versions as follows:

CWnd* GetDlgItem(int nID) const;
void CWnd::GetDlgItem(int nID, HWND* phWnd) const;

To refer to a control in your code, you can also declare a variable for it. There are two types of variable you can use to refer to a control. If you are more interested in the value held by a control, then you can declare a value variable for it. The variable must be a valid type of value that the control can hold. For example, the text in a text-based control (such as an edit box or a combo box) is a CString. Therefore, you can declare a CString variable for the control. If you want to refer to the object as a control and get access to its properties, you should declare the variable as Control.

To help with making that decision, you should use either ClassWizard of MSVC 6 or the Add Member Variable Wizard of MSVC 7. Because the wizard also inserts the appropriate code in the header and source files, you should rely on it instead of manually declaring the variable(s).

If you want to refer to the object as a control and separately refer to its value, you can declare both the Value and the Control variables.

Messages and Events



Introduction to Messages


Some of your applications will be made of various objects. Most of the time, more than one application is running on the computer. These two scenarios mean that the operating system is constantly asked to perform some assignments. Because there can be so many requests presented unpredictably, the operating system leaves it up to the objects to specify what they want, when they want it, and what behavior or result they expect.

The Microsoft Windows operating system cannot predict what kinds of requests one object would need to be taken care of and what type of assignment another object would need. To manage all these assignments and requests, the objects send messages, one message at a time, to the operating system. For this reason, Microsoft Windows is said to be a message-driven operating system.

The messages are divided in various categories but as mentioned already, each object has the responsibility to decide what message to send and when. Therefore, most of the messages we will review here are part of a window frame. Others will be addressed when necessary.

Once a control has composed a message, it must send it to the right target which could be the operating system. In order to send a message, a control must create an event. It is also said to fire an event. To make a distinction between the two, a message's name usually starts with WM_ which stands for Window Message. The name of an event usually starts with On which indicates an action. Remember, the message is what needs to be sent. The event is the action of sending the message.

A Map of Messages


For the compiler to manage messages, they should be included in the class definition. The list of messages starts on a section driven by, but that ends with, the DECLARE_MESSAGE_MAP macro. The section can be created as follows:

#include 
 
class CSimpleFrame : public CFrameWnd
{
public:
        CSimpleFrame();
 
        DECLARE_MESSAGE_MAP()
};

The DECLARE_MESSAGE_MAP macro should be provided at the end of the class definition. The actual messages (as we will review them shortly) should be listed just above the DECLARE_MESSAGE_MAP line. This is mostly a suggestion. In some circumstances, and for any reason, you may want, or have, to provide one message or a few messages under the DECLARE_MESSAGE_MAP line.

To implement the messages, you should/must create a table of messages that your program is using. This table uses two delimiting macros. It starts with a BEGIN_MESSAGE_MAP and ends with an END_MESSAGE_MAP macros. The BEGIN_MESSAGE_MAP macro takes two arguments, the name of your class and the MFC class you derived your class from. An example would be:

BEGIN_MESSAGE_MAP(CSimpleFrame, CFrameWnd)

Like the DECLARE_MESSAGE_MAP macro, END_MESSAGE_MAP takes no argument. Its job is simply to specify the end of the list of messages. The table of messages can be created as follows:

#include 
#include "resource.h"
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        LoadFrame(IDR_MAINFRAME);
}
 
class CMainApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
 
END_MESSAGE_MAP()
 
BOOL CMainApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CMainApp theApp;

There various categories of messages the operating system receives. Some of them come from the keyboard, some from the mouse, and some others from various other origins. For example, some messages are sent by the application itself while some other messages are controlled by the operating.

Practical Learning: Creating a Map of Messages


  1. Create a new and empty Win32 Project located in C:\Programs\MSVC Exercises and set its the Name to Messages1
  2. Specify that you want to Use MFC in a Shared DLL
  3. Create a C++ file and name it Exercise
  4. To create a frame for the window, in the Exercise.cpp file, type the following:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
 
END_MESSAGE_MAP()
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application and return to MSVC

Windows Messages


Window Creation


WM_CREATE: When an object, called a window, is created, the frame that creates the objects sends a message identified as ON_WM_CREATE. Its syntax is:

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

This message calls the CFrameWnd::Create() method to create a window. To do that, it takes one argument, which is a pointer to a CREATESTRUCT class. The CREATESTRUCT class provides all the information needed to create a window. It is defined as follows:

typedef struct tagCREATESTRUCT {
   LPVOID    lpCreateParams;
   HANDLE    hInstance;
   HMENU     hMenu;
   HWND      hwndParent;
   int       cy;
   int       cx;
   int       y;
   int       x;
   LONG      style;
   LPCSTR    lpszName;
   LPCSTR    lpszClass;
   DWORD     dwExStyle;
} CREATESTRUCT;

This class provides the same types of information as the WNDCLASS object. When sending the OnCreate() message, the class is usually created without your intervention but when calling it, you should check that the window has been created. This can be done by checking the result returned by the OnCreate() message from the parent class. If the message returns 0, the window was created. If it returns -1, the class was not created or it would simply be destroyed. This can be done as follows:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        // Create the window and make sure it doesn't return -1
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        // else is implied
        return 0;
}

To use this message, in the class definition, type its syntax. In the message table, type the name of the message ON_WM_CREATE():

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
END_MESSAGE_MAP()

Practical Learning: Creating a Window


  1. To create an ON_WM_CREATE message, change the file as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        // Call the base class to create the window
        if( CFrameWnd::OnCreate(lpCreateStruct) == 0)
        {
               // If the window was successfully created, let the user know
               MessageBox("The window has been created!!!");
                  // Since the window was successfully created, return 0
               return 0;
        }
        // Otherwise, return -1
        return -1;
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application and return to MSVC

Window's Showing State


WM_SHOWWINDOW: After creating a window, it needs to be displayed. Also, if the window was previously hidden, you can decide to show it. On the other hand, if a window is displaying, you may want to hide it, for any reason you judge necessary. To take any of these actions, that is, to show or hide a window, you must send the ON_WM_SHOWWINDOW message. The syntax of this message is:

afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);

When using this message, bShow is a Boolean argument determines what state to apply to the window. If it is TRUE, the window needs to be displayed. If it is FALSE, the window must be hidden.

nStatus is a positive integer that can have one of the following values:


Value

Description


SW_PARENTCLOSING

If the window that sent this message is a frame, the window is being minimized.
If the window that sent this message is hosted by another window, the window is being hidden.


SW_PARENTOPENING

If the window that sent this message is a frame, the window is being restored.
If the window that sent this message is hosted by another window, the window is displaying.


0

The message was sent from a CWnd::ShowWindow() method.

Practical Learning: Showing a Window


  1. To maximize the window at startup, change the program as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_SHOWWINDOW()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        // Call the base class to create the window
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
{
        CFrameWnd::OnShowWindow(bShow, nStatus);
        
        // TODO: Add your message handler code here
        ShowWindow(SW_MAXIMIZE);
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the program and return to MSVC

Window Activation


WM_ACTIVATE: When two or more windows are running on the computer, only one can receive input from the user, that is, only one can actually be directly used at one particular time. Such a window has a title bar with the color identified in Control Panel as Active Window. The other window(s), if any, display(s) its/their title bar with a color called Inactive Window:

To manage this setting, the windows are organized in a 3-dimensional coordinate system and they are incrementally positioned on the Z coordinate, which defines the (0, 0, 0) origin on the screen (actually on the top-left corner of your monitor) with Z coordinate coming from the screen towards you.

In order to use a window other than the one that is active, you must activate it. To do this, you can send a message called ON_WM_ACTIVATE. The syntax of this message is:

afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);

This message indeed does two things: it activates a window of your choice, or brings it to the front, and deactivates the other window(s) or sends it/them to the back of the window that is being activates. The nState argument specifies what action to apply. It is a constant that can assume of the following values:


Value

Description


WA_ACTIVE

Used to activate a window without using the mouse, may be by pressing Alt + Tab


WA_INACTIVE

Used to deactivate a window


WA_CLICKACTIVE

Used to activate a window using the mouse

If this message was sent by the window that is being activated, pWndOther designates the other window, the one being deactivated. If this message was sent by the window that is being deactivated, pWndOther designates the other window, the one being activated.

If the window that sent this message is being restored from its deactivation, pass the bMinimized value as TRUE.

When calling this message, before implementing the custom behavior you want, first call its implementation from the parent class:

void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
        CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
        
        // TODO: Add your message handler code here
}


Practical Learning: Activating a Window


  1. To activate a window that has been created, change the file as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
        afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_SHOWWINDOW()
        ON_WM_ACTIVATE()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        // Call the base class to create the window
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
{
        CFrameWnd::OnShowWindow(bShow, nStatus);
        
        // TODO: Add your message handler code here
        //ShowWindow(SW_SHOW);
}
 
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
        CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
        
        // TODO: Add your message handler code here
        switch( nState )
        {
        case WA_ACTIVE:
               SetWindowText("This window has been activated, without the mouse!");
               break;
        case WA_INACTIVE:
               SetWindowText("This window has been deactivated and cannot be changed now!!");
               break;
        case WA_CLICKACTIVE:
               SetWindowText("This window has been activated using the mouse!!!");
               break;
        }       
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application. While it is displaying, open Notepad
  2. Display each window using the mouse. Then activate your window using Alt+Tab

  1. Return to MSVC

Window Painting


WM_PAINT: Whether you have just created a window or you want to show it, you must ask the operating system to display it, showing its appearance. To display such a window, the operating system would need its location (left and top measures) and its dimension (width and height). This is because the window must be painted. Also, if the window was hidden somewhere such as behind another window or was minimized, when it comes up, the operating system needs to paint it. To do this, the window that needs to be painted must send a message called ON_WM_PAINT. This message does not return anything but in its body, you can define what needs to be painted and how you want the job to be done. The syntax of this message is simply:

afx_msg void OnPaint()

Practical Learning: Using the Paint Message


  1. To use the structure of the WM_PAINT message, change the program as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
        afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
        afx_msg void OnPaint();
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_SHOWWINDOW()
        ON_WM_ACTIVATE()
        ON_WM_PAINT()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
{
        CFrameWnd::OnShowWindow(bShow, nStatus);
        
        // TODO: Add your message handler code here
        //ShowWindow(SW_SHOW);
}
 
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
        CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
        
        // TODO: Add your message handler code here
        switch( nState )
        {
        case WA_ACTIVE:
               SetWindowText("This window has been activated, without the mouse!");
               break;
        case WA_INACTIVE:
               SetWindowText("This window has been deactivated and cannot be changed now!!");
               break;
        case WA_CLICKACTIVE:
               SetWindowText("This window has been activated using the mouse!!!");
               break;
        }       
}
 
void CMainFrame::OnPaint() 
{
        CFrameWnd::OnPaint();
 
        SetWindowText("The window has been painted<==>");
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application and return to MSVC

Window Sizing


WM_SIZE: When using an application, one of the actions a user can perform on a window is to change its size, provided the window allows this. Also, some time to time, if the window allows it, the user can minimize, maximize, or restore a window. Whenever any of these actions occur, the operating system must keep track of the size of a window. When the size of a window has changed, the window sends the ON_WM_SIZE message. Its syntax is:

afx_msg void OnSize(UINT nType, int cx, int cy);

The nType argument specifies what type of action to take. It can have one of the following values:


Value

Description


SIZE_MINIMIZED

The window has been minimized


SIZE_MAXIMIZED

The window has been maximized


SIZE_RESTORED

The window has been restored from being maximized or minimized


SIZE_MAXHIDE

Another window, other than this one, has been maximized


SIZE_MAXSHOW

Another window, other than this one, has been restored from being maximized or minimized

The cx argument specifies the new width of the client area of the window

The cy argument specifies the new height of the client area of the window.

To use this message, you should first call its implementation in the parent class before implementing the behavior you want. This can be done as follows:

void CAnyWindow::OnSize(UINT nType, int cx, int cy) 
{
        CParentClass::OnSize(nType, cx, cy);
        
        // TODO: Add your message handler code here
}

WM_SIZING: While the user is changing the size of a window, a message called ON_WM_SIZING is being sent. Its syntax is:

afx_msg void OnSizing(UINT nSide, LPRECT lpRect);

When a user is resizing a window, he or she typically drags one of the borders or corners on a direction of his or her choice. The first argument, nSize, indicates what edge is being moved when resizing the window. It can have one of the following values:


Value

Description


WMSZ_BOTTOM

Bottom edge


WMSZ_BOTTOMLEFT

Bottom-left corner


WMSZ_BOTTOMRIGHT

Bottom-right corner


WMSZ_LEFT

Left edge


WMSZ_RIGHT

Right edge


WMSZ_TOP

Top edge


WMSZ_TOPLEFT

Top-left corner


WMSZ_TOPRIGHT

Top-right corner

The second argument, lpRect, is the new rectangle that will enclose the window after the window has been moved, resized, or restored.

Window Moving


WM_MOVE: When a window has been moved, the operating system needs to update its location. Therefore, the window sends a message called ON_WM_MOVE. Its syntax is:

afx_msg void OnMove(int x, int y);

The first argument of this message specifies the left horizontal location of the left border of the window after the window has been moved. The second argument represents the vertical position of the top border of the window after the window has been moved.

If you want to send this message, you should first call its implementation in the parent class

WM_MOVING: While the user is moving a window, it (the window sends) an ON_WM_MOVING message. Its syntax is:

afx_msg void OnMoving( UINT nSide, LPRECT lpRect );

The first argument, nSide, is the edge of the window that is being moved. It is the same as for the ON_MOVE message.

The lpRect is the target dimension of the window that is being moved. That is, it contains the new dimensions of the window as it is being moved.

Practical Learning: Moving a Window


  1. To see the effect of moving a window, change the file as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
        afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
        afx_msg void OnPaint();
        afx_msg void OnSize(UINT nType, int cx, int cy);
        afx_msg void OnMove(int x, int y);
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_SHOWWINDOW()
        ON_WM_ACTIVATE()
        ON_WM_PAINT()
        ON_WM_SIZE()
        ON_WM_MOVE()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) 
{
        CFrameWnd::OnShowWindow(bShow, nStatus);
        
        // TODO: Add your message handler code here
        //ShowWindow(SW_SHOW);
}
 
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
        CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
        
        // TODO: Add your message handler code here
        switch( nState )
        {
        case WA_ACTIVE:
               SetWindowText("This window has been activated, without the mouse!");
               break;
        case WA_INACTIVE:
               SetWindowText("This window has been deactivated and cannot be changed now!!");
               break;
        case WA_CLICKACTIVE:
               SetWindowText("This window has been activated using the mouse!!!");
               break;
        }       
}
 
void CMainFrame::OnPaint() 
{
        CFrameWnd::OnPaint();
 
        SetWindowText("The window has been painted<==>");
}
 
void CMainFrame::OnSize(UINT nType, int cx, int cy) 
{
/*      CMainFrame::OnSize(nType, cx, cy);
        
        // TODO: Add your message handler code here
        char *MsgToShow = new char[20];
        char *MsgCoord  = new char[20];
        
        switch(nType)
        {
        case SIZE_MINIMIZED:
               strcpy(MsgToShow, "Minimized ");
               break;
        case SIZE_MAXIMIZED:
               strcpy(MsgToShow, "Maximized ");
               break;
        case SIZE_RESTORED:
               strcpy(MsgToShow, "Restored ");
               break;
        case SIZE_MAXHIDE:
               strcpy(MsgToShow, "Maximized Not Me ");
               break;
        case SIZE_MAXSHOW:
               strcpy(MsgToShow, "Restored Not Me ");
               break;
        }
 
        sprintf(MsgCoord, "Left = %d | Top = %d", cx, cy);
        strcat(MsgToShow, MsgCoord);
        SetWindowText(MsgToShow);
*/
}
 
void CMainFrame::OnMove(int x, int y) 
{
        CFrameWnd::OnMove(x, y);
        
        // TODO: Add your message handler code here
        char *MsgCoord  = new char[20];
 
        sprintf(MsgCoord, "Left = %d | Top = %d", x, y);
        
        SetWindowText(MsgCoord);
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application:

  2. Return to MSVC

Window Destruction


WM_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it. The message sent is called ON_WN_DESTROY and its syntax is:

afx_msg void OnDestroy( );

This message takes no argument but you can use its body to do any last minute assignment as needed. For example, you can use it either to prevent the window from being closed or you can enquire whether the user really wants to close the window.

Command Messages


Definition


One of the main features of a graphical application is to present Windows controls and resources that allow the user to interact with the machine. Examples of controls that we will learn are buttons, list boxes, combo boxes, etc. One type of resource we introduced in the previous lesson is the menu. Such controls and resources can initiate their own messages when the user clicks them. A message that emanates from a Windows control or a resource is called a command message.

Creating a Command Message


You can start by declaring a framework method. Here is an example:

afx_msg void OnLetItGo();

Then you can define the method as you see fit:

void CMainFrame::OnLetItGo()
{
        // Something to do here
}

The framework allows you to associate a member function to a command message. This is done using the ON_COMMAND macro. Its syntax:

ON_COMMAND(IDentifier, MethodName)

The first argument, IDentifier, of this macro must be the identifier of the menu item or Windows control you want to associate with a method.

The second argument, MethodName, must be the name of the member function that will implement the action of the menu item or Windows control such a button.

Imagine you have a menu item IDentified as ID_ACTION_LETITGO that you want to associate with the above OnLetItGo() method. You can use the ON_COMMAND macro as follows:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_COMMAND(ID_ACTION_LETITGO, OnLetItGo)
END_MESSAGE_MAP()

In the same way, you can create as many command messages as necessary.

Keyboard Messages


Introduction


A keyboard is a hardware object attached to the computer. By default, it is used to enter recognizable symbols, letters, and other characters on a control. Each key on the keyboard displays a symbol, a letter, or a combination of those, to give an indication of what the key could be used for.

The user typically presses a key, which sends a signal to a program. The signal is analyzed to find its meaning. If the program or control that has focus is equipped to deal with the signal, it may produce the expected result. If the program or control cannot figure out what to do, it ignores the action.

Each key has a code that the operating system can recognize. This code is known as the virtual key code and they are as follows:


Virtual Key

Used for

Virtual Key

Used for

VK_F1

F1

VK_F2

F2

VK_F3

F3

VK_F4

F4

VK_F5

F5

VK_F6

F6

VK_F7

F7

VK_F8

F8

VK_F9

F9

VK_F10

F10

VK_F11

F11

VK_F12

F12

VK_SCROLL

Scroll Lock

VK_SNAPSHOT

Prt Scrn (Depends on keyboard)

VK_PAUSE

Pause/Break

VK_TAB

Tab

VK_BACK

Backspace

VK_CAPITAL

Caps Lock

VK_SHIFT

Shift

VK_CONTROL

Ctrl

VK_MENU

Alt

VK_ESCAPE

Escape

K_RETURN

Enter

VK_SPACE

Space Bar

VK_INSERT

Insert

VK_HOME

Home

VK_PRIOR

Page Up

VK_DELETE

Delete

VK_END

End

VK_NEXT

Page Down

VK_UP

Up Arrow Key

VK_RIGHT

Right Arrow Key

VK_DOWN

Down Arrow Key

VK_LEFT

Left Arrow Key

VK_LWIN

Left Windows Key

VK_RWIN

Right Windows Key

VK_APPS

Applications Key



The following keys apply to the Numeric Keypad


VK_NUMLOCK

Num Lock



VK_NUMPAD0

0

VK_NUMPAD1

1

VK_NUMPAD2

2

VK_NUMPAD3

3

VK_NUMPAD4

4

VK_NUMPAD5

5

VK_NUMPAD6

6

VK_NUMPAD7

7

VK_NUMPAD8

8

VK_NUMPAD9

9

VK_DIVIDE

/

VK_MULTIPLY

*

VK_SUBTRACT

-

VK_ADD

+

VK_SEPARATOR


VK_DECIMAL

.

There are actually more keys than that but the above are the most frequently used.

Practical Learning: Introducing Keyboard Messages


  1. Create a new and empty Win32 Project located in C:\Programs\MSVC Exercises and set its the Name to Messages2
  2. Specify that you want to Use MFC in a Shared DLL
  3. Create a C++ file and name it Exercise
  4. To create a frame for the window, in the Exercise.cpp file, type the following:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
 
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application and return to MSVC

The Key Down Effect


When we think of the keyboard, the first thing that comes in mind if to press a key. When a keyboard key is pressed, a message called WM_KEYDOWN. Its syntax is:

afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );

The first argument, nChar, specifies the virtual code of the key that was pressed.

The second argument, nRepCnt, specifies the number of times counted repeatedly as the key was held down.

The nFlags argument specifies the scan code, extended-key flag, context code, previous key-state flag, and transition-state flag.

Practical Learning: Sending Key Down Messages


  1. To experiment with the ON_KEYDOWN message, change the file as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
 
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_KEYDOWN()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
        switch(nChar)
        {
        case VK_RETURN:
               SetWindowText("You pressed Enter");
               break;
        case VK_F1:
               SetWindowText("Help is not available at the moment");
               break;
        case VK_DELETE:
               SetWindowText("Can't Delete This");
               break;
        default:
               SetWindowText("Whatever");
        }
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the application and return to MSVC

The Key Up Effect


When we think of the keyboard, the first thing that comes in mind might refer to typing, which consists of pressing a key and releasing it immediately. As this is done, a key is pressed down and brought back up. When the user is releasing a key a WM_KEYUP message is sent. Its syntax is:

afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

The first argument, nChar, is the code of the key that was pressed.

The second argument, nRepCnt, specifies the number of times counted repeatedly as the key was held down.

The nFlags argument specifies the scan code, extended-key flag, context code, previous key-state flag, and transition-state flag.

Mouse Messages


Introduction


The mouse is another object that is attached to the computer allowing the user to interact with the machine. The mouse and the keyboard can each accomplish some tasks that are not normally available on the other and both can accomplish some tasks the same way.

The mouse is equipped with two, three, or more buttons. When a mouse has two buttons, one is usually located on the left and the other is located on the right. When a mouse has three buttons, one is in the middle of the other two. The mouse is used to select a point or position on the screen. Once the user has located an item, which could also be an empty space, a letter or a word, he or she would position the mouse pointer on it. To actually use the mouse, the user would press either the left, the middle (if any), or the right button. If the user presses the left button once, this action is called Click. If the user presses the right mouse button, the action is referred to as Right-Click. If the user presses the left button twice and very fast, the action is called Double-Click.

Mouse-Down Messages


Imagine the user has located a position or an item on a document and presses one of the mouse buttons. While the button is pressed and is down, a button-down message is sent, depending on the button that was pressed.

If the left mouse button was pressed, an ON_WM_LBUTTONDOWN message is sent. The syntax of this message is:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

If the right mouse button was pressed, an ON_WM_RBUTTONDOWN message is sent. Its syntax is:

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

The first argument, nFlags, specifies what button is down or what keyboard key and what mouse button are down. It is a constant integer that can have one of the following values:


Value

Description


MK_CONTROL

A Ctrl key is held down


MK_LBUTTON

The left mouse button is down


MK_MBUTTON

The middle mouse button is down


MK_RBUTTON

The right mouse button is down


MK_SHIFT

A Shift key is held down

The point argument specifies the measure from the left and the top borders of the window to the mouse pointer.

Practical Learning: Sending a Mouse Down Message


  1. To experiment with the mouse down effect, change the program as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_KEYDOWN()
        ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
        switch(nChar)
        {
        case VK_RETURN:
               SetWindowText("You pressed Enter");
               break;
        case VK_F1:
               SetWindowText("Help is not available at the moment");
               break;
        case VK_DELETE:
               SetWindowText("Can't Delete This");
               break;
        default:
               SetWindowText("Whatever");
        }
}
 
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) 
{
        char *MsgCoord  = new char[20];
 
        sprintf(MsgCoord, "Left Button at P(%d, %d)", point.x, point.y);
        
        SetWindowText(MsgCoord);
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Test the program:

  2. Return to MSVC

The Mouse-Up Messages


After pressing a mouse button, the user usually releases it. While the button is being released, a button-up message is sent and it depends on the button, left or right, that was down.

If the left mouse is being released, the ON_WM_LBUTTONUP message is sent. Its syntax is:

afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

If the right mouse is being released, the ON_WM_TBUTTONUP message is sent. Its syntax is:

afx_msg void OnRButtonUp(UINT nFlags, CPoint point);

The first argument, nFlags, specifies what button, right or middle, is down or what keyboard key and what mouse button were down. It is a constant integer that can have one of the following values:


Value

Description


MK_CONTROL

A Ctrl key was held down


MK_MBUTTON

The middle mouse button was down


MK_RBUTTON

The right mouse button was down


MK_SHIFT

A Shift key was held

The point argument specifies the measure from the (0, 0) origin of the window to the mouse pointer.

Practical Learning: Sending a Mouse Down Message


  1. To experiment with a mouse up message, change the program as follows:
#include 
 
class CMainFrame : public CFrameWnd
{
public:
        CMainFrame ();
 
protected:
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
        afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
 
        DECLARE_MESSAGE_MAP()
};
 
CMainFrame::CMainFrame()
{
        // Create the window's frame
        Create(NULL, "Windows Application", WS_OVERLAPPEDWINDOW,
               CRect(120, 100, 700, 480), NULL);
}
 
class CExerciseApp: public CWinApp
{
public:
        BOOL InitInstance();
};
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_KEYDOWN()
        ON_WM_LBUTTONDOWN()
        ON_WM_RBUTTONUP()
END_MESSAGE_MAP()
 
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
               return -1;
        return 0;
}
 
void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
        switch(nChar)
        {
        case VK_RETURN:
               SetWindowText("You pressed Enter");
               break;
        case VK_F1:
               SetWindowText("Help is not available at the moment");
               break;
        case VK_DELETE:
               SetWindowText("Can't Delete This");
               break;
        default:
               SetWindowText("Whatever");
        }
}
 
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) 
{
        char *MsgCoord  = new char[20];
 
        sprintf(MsgCoord, "Left Button at P(%d, %d)", point.x, point.y);
        
        SetWindowText(MsgCoord);
}
 
void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) 
{
        SetWindowText("Right Mouse Button Up");
}
 
BOOL CExerciseApp::InitInstance()
{
        m_pMainWnd = new CMainFrame ;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
 
        return TRUE;
}
 
CExerciseApp theApp;
  1. Execute the program. To test it, click in the middle of the window and hold the mouse down
  2. Then release the mouse. Notice that the title bar displays the new message only when the mouse is up.
  3. Return to MSVC

The Double-Click Message


Instead of pressing and simply releasing a mouse button, a classic action the user can perform with the mouse is to double-click an object. When this is done, a double-click message is sent. The message to consider actually depends on the button that was double-pressed.

If the double-click was performed using the left mouse button, the WM_LBUTTONDBLCLK message is sent and its syntax is:

afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);

If the action was performed using the right mouse button, the WM_RBUTTONDBLCLK message would be sent. Its syntax is:

afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);

In both cases the nFlags argument specifies the button that was double-clicked. This argument can have one of the following values:


Value

Description


MK_CONTROL

A Ctrl key was held down when the user double-clicked


MK_LBUTTON

The left mouse button is down


MK_MBUTTON

The middle mouse button is down


MK_RBUTTON

The right mouse button is down


MK_SHIFT

A Shift key was held down when the user double-clicked

The point argument specifies the location of the mouse pointer in x (horizontal) and y (vertical) coordinates.

Mouse Moving


After pressing one of the mouse buttons, depending on the requirement, the use may not need to immediately release the button. Another action performed with the mouse consists of clicking and holding the mouse button down, then dragging in a chosen direction. This action refers to the mouse moving. When this is done a WM_MOUSEMOVE message is sent. Its syntax is:

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

The nFlags argument specifies what button is held down or what key is pressed in combination with the button that is held down while the mouse pointer is moving. This argument can have one of the following values:


Value

While the mouse is moving


MK_CONTROL

A Ctrl key is held down


MK_LBUTTON

The left mouse button is down


MK_MBUTTON

The middle mouse button is down


MK_RBUTTON

The right mouse button is down


MK_SHIFT

A Shift key was held down

The point argument specifies the current location of the mouse pointer in x (horizontal) and y (vertical) coordinates at the time the message is captured.

Conditional Messages


Introduction


The messages we have used so far belong to specific events generated at a particular time by a window. Sometimes in the middle of doing something, you may want to send a message regardless of what is going on. This is made possible by a function called SendMessage(). Actually, there are two SendMessage() versions available.

The Win32 API version of the SendMessage() function has the following syntax:

LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

The MFC version is defined as follows:

LRESULT SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);

Because the Win32 version is considered global, if you want to use it, you must precede it with the scope access operator "::" as in:

::SendMessage(WhatToDo);

The hWnd argument is the object or control that is sending the message.

The Msg argument is the message to be sent.

The wParam and the lParam values depend on the message that is being sent.

The advantage of using the SendMessage() function is that, when sending this message, it would target the procedure that can perform the task and this function would return only after its message has been processed.

Sending Messages


In order to send a message using the SendMessage() function, you must know what message you are sending and what that message needs in order to be complete. For example, to change the caption of a window at any time, you can use the WM_SETTEXT message. The syntax to use would be:

SendMessage(WM_SETTEXT, wParam, lParam);

Obviously you would need to provide the text for the caption you are trying to change. This string is carried by the lParam argument as a null-terminated string. For this message, the wParam is ignored.

Practical LearningPractical Learning: Sending Messages


  1. To process a message using the SendMessage() function, change the OnRButtonUp() event as follows:
void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) 
{
        const char *Msg = "This message was sent";
        SendMessage(WM_SETTEXT, 0, (LPARAM)(LPCTSTR)Msg);
}
  1. Test the application and return to MSVC