Every object in Microsoft Windows is assigned a positive number named a handle. This number allows the operating system to communicate with the object. In the same way, the number allows the object to identify itself when other objects of its applications or when the operating system needs to know. In Microsoft Windows, the handle of an object is identified with a class named HWND. Many times in your code, you will need to get, and refer to, the handle of an object.
There are two particularly important pieces of information about every control of your application. The information stored in the control and the action or type of action the user can perform on that control. At one time in the life of an application, a control holds a value that can be of particular interest either to you or to the user. On the other hand, when interacting with the computer, based on your application, the user will usually face different types of controls that do various things and produce different results. These are two features of controls (their values and the actions the user can perform on them) that you should know as much as possible, about the controls you choose to involve in your application. To support the ability to create a control, the Win32 library provides two functions named CreateWindow and CreateWindowEx. The syntaxes of these functions are:
In most cases, you can use either of these functions. When doing this, you must specify the control's name. To help with this, the Win32 library provides already defined names of classes you can use to create a control. When creating a window, you need to declare its handle and initialize it with the CreateWindow() or the CreateWindowEx() function. If the window is created successfully, the function returns a window handle. If the control created was a parent, its handle can be used as the hWndParent argument. The reason you declare a handle to the parent window is to allow you to refer to it later on. In the same way, if you need to refer to any control that is part of your application, you should define its own handle.
The Microsoft Foundation Class library, MFC, is a Microsoft custom implementation of the Win32 library. While programming in Win32 is mostly done manually by writing code, Microsoft Visual Studio makes it possible to visually create an application by adding objects to a host such as a dialog box. Still, most of the time you will need to know the class used to manage an object. The most fundamental class used for visible objects in the MFC is called CWnd. The CWnd class is derived from the CCmdTarget class:
As we will see throughout our lessons, the CWnd class provides all, or almost all, of the functionality you need to create or manage a Windows control. When necessary, we will mentioned the CreateWindow() and/or the CreateWindowEx() function to explain a concept, but most of the time, you will use either CWnd or one of its derived classes to take necessary action. To assist you with creating a control, the CWnd class is equipped with a method named Create that corresponds to the Win32's CreateWindow() function. The syntax of the CWnd::Create() function is: virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); To provide the ability to apply extended styles to a control, the CWnd class is equipped with a CreateEx() method that is overloaded with two versions. Their syntaxes are: virtual 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 ); virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL);
To create a control, you must specify its name. To do this, you have various options. The Win32 library provides already defined names of classes you can use to create a control. These classes are:
To use one of these classes, you have various options. At design time, in the Toolbox, you can click the Custom Control button and click the dialog box. In the Properties window, click Class and type the class name. If you are programmatically creating the control, pass its name as string to the lpszClassName argument of the Create() or the CreateEx() methods. Here is an example that would start an edit box: void CSecondDlg::OnThirdControl() { CWnd *memo = new CWnd; memo->Create("BUTTON", ); } The other option you have is to specify the class name as NULL. In this case, the compiler would use a default name: void Whatever () { CWnd *second = new CWnd; second->Create(NULL, ); }
The window name is a default string that displays on the control when the control comes up. In some cases, this string displays as caption on the title bar of a dialog box. This property is different for various controls. To set the default text of a control, you can either do this when creating the control or change its text at any time. This depends 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() { 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. When you create a parent window, if you want to refer to that parent control, you should use the value returned by the CreateWindow() or the CreateWindowEx() function, which is an HWND value. If you are creating an MFC application, you usually call the Create() method of the window you are creating. As the parent of all window classes of an MFC application, CWnd provides a member variable called m_hWnd. It is defined as follows: HWND m_hWnd; This public variable is inherited by all classes that are based on CWnd, which includes all MFC window objects. Consequently, m_hWnd gives you access to the handle to the window you have created. For example, the CDialog class, which is based on CWnd but is the most used host of Windows controls, can provide its m_hWnd variable as the parent of its control. In the same way, to get a handle to any control of your application, access its m_hWnd member variable. If you had created a window using the Win32 API's CreateWindow() or CreateWindowEx() function, or if for any reason an HWND object exists in your application, you can convert such a window to a CWnd pointer using the CWnd::FromHandle() method. Its syntax is: static CWnd* PASCAL FromHandle(HWND hWnd); Here is an example: HWND ThisWnd;
ThisWnd = CreateWindow(. . .);
CWnd *NewWnd;
NewWnd->FromHandle(ThisWnd);
Once a control has been created, you and your users can exploit it. On one hand, the user can type a value, select text, scroll, or click something. One of your jobs as a programmer is to predict as many actions as the user may want to perform on your control(s) and take appropriate actions. One way you can refer to a control in your code consists of first providing it with an identifier. Another prerequisite you can take is to declare and associate a control and/or a value variable for the control. Sometimes you will not have declared a control variable for a control but at one time you need to refer to it. One way you can do this is to use the control's identifier and cast it to its corresponding class. This can be taken care of by calling the CWnd::GetDlgItem() method. It comes in two versions as follows: CWnd* GetDlgItem(int nID) const; void CWnd::GetDlgItem(int nID, HWND* phWnd) const; By providing the nID argument as the identifier of the control to this method, you can get a pointer to its class. To do this, you can declare a pointer to the class of the control, then call the GetDlgItem() method. Because GetDlgItem() returns a CWnd pointer, using the features of inheritance, cast this return value to the class of the control.
Every Windows control in Microsoft Windows should provide a way to identify itself, to the operating system and to other objects on the computer. In Lesson 5, when introducing dialog boxes, we saw how to create a resource file. In such a resource file, you can create an identifier for a control. There are two main ways you can create an identifier for a control:
If you want to avoid providing an identification for a control, you may have to use the Win32 API's CreateWindow() or CreateWindowEx() function to create the control. Imagine a control with its identifier has already been added to a dialog box but you want to change that identifier, for any reason you judge necessary. To assist you with this, the CWnd class is equipped with the SetDlgCtrlID() method. Its syntax is: int SetDlgCtrlID(int nID); This method assigns or changes the identifier of the control that called it. Imagine the control variable of a control is named m_Edition, you can assign a new identifier to it as follows: BOOL CDlgControls::OnInitDialog() { CDialog::OnInitDialog(); m_Edition.SetDlgCtrlID(0x1882); return TRUE; } If a control has been created and you need its identifier, you can find it out by calling the CWnd::GetDlgCtrlID() method. Its syntax is: int GetDlgCtrlID() const; This method simply returns the identifier of the control that called it. The value is returned as an integer. You will mostly use this method to find out if the identifier of a control matches the one the user has just accessed.
In the previous lessons, we reviewed some of the characteristics of a classic container such as a dialog box. In the next sections, we will review some of the characteristics of child controls. Based on their relationship in the application, a parent and a child must communicate and share some behaviors. To make this happen, you will need to identify or get a reference to the application, to the parent control, or to the control itself. Probably the most fundamental piece of information you must know about an application is its instance.
If you create an MFC application using the CWinApp class, when the application comes up, it creates an instance, which is usually the hInstance in Win32. Sometimes you will need to refer to the instance of your application. To help you with this, CWinApp class is equipped with a property named m_hInstance. Alternatively, for an MFC application, you can call the AfxGetInstanceHandle() global function to get a handle to the instance of your application. This could be accessed as follows: BOOL CDialog1Dlg::OnInitDialog() { CDialog::OnInitDialog(); HINSTANCE InstanceOfThisApp = AfxGetInstanceHandle(); return TRUE; }
To help you get information about a control, the Win32 library provides the GetWindowLong() function. Their syntaxes are: LONG GetWindowLong(HWND hWnd, int nIndex); After this function executes, it returns a LONG value. If you prefer to get a pointer and if you are working on a 64-bit environ, use the GetWindowLongPtr() function instead. Its syntax is: LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex); The first argument, hWnd, is a handle to the control whose information you are seeking. The nIndex argument specifies the type of information you are looking for. Its possible values are:
After calling this function and specifying the type of information you need, it returns a (constant) value you can use as you see fit. Here are two methods of getting a handle to the instance of the application. The second example uses the GetWindowLong() function: BOOL CExerciseDlg::OnInitDialog() { CDialog::OnInitDialog(); HINSTANCE Instance1 = AfxGetInstanceHandle(); LONG Instance2 = GetWindowLong(m_hWnd, GWL_HINSTANCE); m_Instance1.Format("%ld", Instance1); m_Instance2.Format("%ld", Instance2); UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control }
We will see how to define the properties, styles, and other characteristics when creating a control. While the user is interacting with the computer using your application, you may need to change some of these attributes of a window. To change the value of an aspect of the window, you can call the SetWindowLong() function. Its syntax is: LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong); If you want to work with a pointer instead of a value, you can use the SetWindowLongPtr() function. Its syntax is: LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong); The hWnd argument is a handle to the window whose informtation you want to change. The value of nIndex species the type of information you want to change. It can have the following values:
If the hWnd argument represents a dialog box, the nIndex argument can also have the following values:
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|