Programming Microsoft Windows Ce Net 3Rd [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming Microsoft Windows Ce Net 3Rd [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






Hello3

Enough review. It's time to jump into a full-fledged Windows application, Hello3. While the entire program files for this and all examples in the book are available in the companion CD-ROM, I suggest that, as in the earlier example, you avoid simply loading the project file from the CD and instead type in the entire example by hand. By performing this somewhat tedious task, you'll see the differences in the development process as well as the subtle program differences between standard Win32 programs and Windows CE programs. Listing 1-3 contains the complete source code for Hello3.

Listing 1-3: The Hello3 program







Hello3.cpp
//======================================================================
// Hello3 - A simple application for Windows CE
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include <windows.h> // For all that Windows stuff
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
//======================================================================
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc;
HWND hWnd;
MSG msg;
// Register application main window class.
wc.style = 0; // Window style
wc.lpfnWndProc = MainWndProc; // Callback function
wc.cbClsExtra = 0; // Extra class data
wc.cbWndExtra = 0; // Extra window data
wc.hInstance = hInstance; // Owner handle
wc.hIcon = NULL, // Application icon
wc.hCursor = LoadCursor (NULL, IDC_ARROW);// Default cursor
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL; // Menu name
wc.lpszClassName = TEXT("MyClass"); // Window class name
if (RegisterClass (&wc) == 0) return -1;
// Create main window.
hWnd = CreateWindowEx(WS_EX_NODRAG, // Ex style flags
TEXT("MyClass"), // Window class
TEXT("Hello"), // Window title
// Style flags
WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, // x position
CW_USEDEFAULT, // y position
CW_USEDEFAULT, // Initial width
CW_USEDEFAULT, // Initial height
NULL, // Parent
NULL, // Menu, must be null
hInstance, // Application instance
NULL); // Pointer to create
// parameters
if (!IsWindow (hWnd)) return -2; // Fail code if not created.
// Standard show and update calls
ShowWindow (hWnd, nCmdShow);
UpdateWindow (hWnd);
// Application message loop
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// Instance cleanup
return msg.wParam;
}
//======================================================================
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
PAINTSTRUCT ps;
RECT rect;
HDC hdc;
switch (wMsg) {
case WM_PAINT:
// Get the size of the client rectangle
GetClientRect (hWnd, &rect);
hdc = BeginPaint (hWnd, &ps);
DrawText (hdc, TEXT ("Hello Windows CE!"), -1, &rect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint (hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage (0);
break;
}
return DefWindowProc (hWnd, wMsg, wParam, lParam);
}











Hello3 shows all aspects of a Windows program, from registering the window class to the creation of the window to the window procedure. Hello3 has the same entry point, WinMain, as the first two examples; but because it creates its own window, it must register a window class for the main window, create the window, and provide a message loop to process the messages for the window.


Registering the Window Class


In WinMain, Hello3 registers the window class for the main window. Registering a window class is simply a matter of filling out a rather extensive structure describing the class and calling the RegisterClass function. RegisterClass and the WNDCLASS structure are defined as follows:

ATOM RegisterClass (const WNDCLASS *lpWndClass);
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;

The parameters assigned to the fields of the WNDCLASS structure define how all instances of the main window for Hello3 will behave. The initial field, style, sets the class style for the window. In Windows CE, the class styles are limited to the following:



CS_GLOBALCLASSindicates that the class is global. This flag is provided only for compatibility because all window classes in Windows CE are process global.



CS_HREDRAWtells the system to force a repaint of the window if the window is sized horizontally.



CS_VREDRAWtells the system to force a repaint of the window if the window is sized vertically.



CS_NOCLOSEdisables the Close button if one is present on the title bar.



CS_PARENTDCcauses a window to use its parent's device context.



CS_DBLCLKSenables notification of double-clicks (double-taps under Windows CE) to be passed to the parent window.



The lpfnWndProc field should be loaded with the address of the window's window procedure. Because this field is typed as a pointer to a window procedure, the declaration to the procedure must be defined in the source code before the field is set. Otherwise, the compiler's type checker will flag this line with a warning.

The cbClsExtra field allows the programmer to add extra space in the class structure to store class-specific data known only to the application. The cbWndExtra field is much handier. This field adds space to the Windows internal structure responsible for maintaining the state of each instance of a window. Instead of storing large amounts of data in the window structure itself, an application should store a pointer to an application-specific structure that contains the data unique to each instance of the window. Under Windows CE, both the cbClsExtra and cbWndExtra fields must be multiples of 4 bytes.

The hInstance field must be filled with the program's instance handle, which specifies the owning process of the window. The hIcon field is set to the handle of the window's default icon. The hIcon field isn't supported under Windows CE and should be set to NULL. (In Windows CE, the icon for the class is set after the first window of this class is created. For Hello3, however, no icon is supplied, and unlike other versions of Windows, Windows CE doesn't have any predefined icons that can be loaded.)

Unless the application being developed is designed for a Windows CE system with a mouse, the next field, hCursor, must be set to NULL. Fortunately, the function call LoadCursor (IDC_ARROW) returns NULL if the system doesn't support cursors.

The hbrBackground field specifies how Windows CE draws the background of the window. Windows uses the brush, a small predefined array of pixels, specified in this field to draw the background of the window. Windows CE provides a number of predefined brushes that you can load using the GetStockObject function. If the hbrBackground field is NULL, the window must handle the WM_ERASEBKGND message sent to the window telling it to redraw the background of the window.

The lpszMenuName field must be set to NULL because Windows CE doesn't support windows directly having a menu. In Windows CE, menus are provided by command bar, command band, or menu bar controls that the main window can create.

Finally the lpszClassName parameter is set to a programmer-defined string that identifies the class name to Windows. Hello3 uses the string "MyClass".

After the entire WNDCLASS structure has been filled out, the RegisterClass function is called with a pointer to the WNDCLASS structure as its only parameter. If the function is successful, a value identifying the window class is returned. If the function fails, the function returns 0.


Creating the Window


Once the window class has been registered successfully, the main window can be created. All Windows programmers learn early in their Windows programming lives the CreateWindow and CreateWindowEx function calls. The prototype for CreateWindowEx is as follows:

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);

Although the number of parameters looks daunting, the parameters are fairly logical once you learn them. The first parameter is the extended style flags. The extended style flags supported by Windows CE are as follows:



WS_EX_TOPMOSTWindow is topmost.



WS_EX_WINDOWEDGEWindow has a raised edge.



WS_EX_CLIENTEDGEWindow has a sunken edge.



WS_EX_STATICEDGE3D look for static windows.



WS_EX_OVERLAPPEDWINDOWCombines WS_EX_WINDOWEDGE and WS_EX_CLIENTEDGE.



WS_EX_CAPTIONOKBUTTONWindow has an OK button on caption.



WS_EX_CONTEXTHELPWindow has help button on caption.



WS_EX_NOACTIVATEWindow is not activated when clicked.



WS_EX_NOANIMATIONTop-level window will not have exploding rectangles when created nor have a button on the taskbar.



WS_EX_NODRAGPrevents window from being moved.



The dwExStyle parameter is the only difference between CreateWindowEx and CreateWindow. In fact, if you look at the declaration of CreateWindow in the Windows CE header files, it's simply a call to CreateWindowEx with the dwExStyle parameter set to 0.

The second parameter is the name of the window class of which our window will be an instance. In the case of Hello3, the class name is MyClass, which matches the name of the class registered in RegisterClass.

The next field is referred to as the window text. In other versions of Windows, this is the text that would appear on the title bar of a standard window. On H/PCs, main windows rarely have title bars; this text is used only on the taskbar button for the window. On the Pocket PC, however, this text is shown on the navigation bar at the top of the display. The text is couched in a TEXT macro, which ensures that the string will be converted to Unicode under Windows CE.

The style flags specify the initial styles for the window. The style flags are used both for general styles that are relevant to all windows in the system and for class-specific styles, such as those that specify the style of a button or a list box. In this case, all we need to specify is that the window be created initially visible with the WS_VISIBLE flag. Experienced Win32 programmers should refer to the documentation for CreateWindow because a number of window style flags aren't supported under Windows CE.

The next four fields specify the initial position and size of the window. Since most applications under Windows CE are full-screen windows, the size and position fields are set to default values, which are indicated by the CW_USEDEFAULT flag in each of the fields. The default value settings create a window that is sized to fit the entire screen under the current versions of Windows CE. Be careful not to assume any particular screen size for a Windows CE device because different implementations have different screen sizes.

The next field is set to the handle of the parent window. Because this is the top-level window, the parent window field is set to NULL. The menu field is also set to NULL because Windows CE does not support menus on top-level windows.

The hInstance parameter is the same instance handle that was passed to the program. Creation of windows is one case in which that instance handle, saved at the start of the routine, comes in handy. The final parameter is a pointer that can be used to pass data from the CreateWindow call to the window procedure during the WM_CREATE message. In this example, no additional data needs to be passed, so the parameter is set to NULL.

If successful, the CreateWindow call returns the handle to the window just created, or it returns 0 if an error occurred during the function. That window handle is then used in the two statements (ShowWindow and UpdateWindow) just after the error-checking if statement. The ShowWindow function modifies the state of the window to conform with the state given in the nCmdShow parameter passed to WinMain. The UpdateWindow function forces Windows to send a WM_PAINT message to the window that has just been created.


The Message Loop


After the main window has been created, WinMain enters the message loop, which is the heart of every Windows application. Hello3's message loop is shown at the top of the next page.

while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}

The loop is simple: GetMessage is called to get the next message in the application's message queue. If no message is available, the call waits, blocking that application's thread until a message is available. When a message is available, the call returns with the message data contained in a MSG structure. The MSG structure itself contains fields that identify the message, provide any message-specific parameters, and identify the last point on the screen touched by the pen before the message was sent. This location information is different from the standard Win32 message point data in that in Windows XP the point returned is the current mouse position instead of the last point clicked (or tapped, as in Windows CE).

The TranslateMessage function translates appropriate keyboard messages into a character message. (I'll talk about others of these filter messages, such as IsDialogMsg, later.) The DispatchMessage function then tells Windows to forward the message to the appropriate window in the application.

This GetMessage, TranslateMessage, DispatchMessage loop continues until GetMessage receives a WM_QUIT message, which, unlike all other messages, causes GetMessage to return 0. As can be seen from the while clause, the return value 0 by GetMessage causes the loop to terminate.

After the message loop terminates, the program can do little else but clean up and exit. In the case of Hello3, the program simply returns from WinMain. The value returned by WinMain becomes the return code of the program. Traditionally, the return value is the value in the wParam parameter of the last message (WM_QUIT). The wParam value of WM_QUIT is set when that message is sent in response to a PostQuitMessage call made by the application.


The Window Procedure


The messages sent or posted to the Hello3 main window are sent to the procedure MainWndProc. MainWndProc, like all window procedures, is prototyped as follows:

LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam, 
LPARAM lParam);

The LRESULT return type is actually just a long (a long is a 32-bit value under Windows) but is typed this way to provide a level of indirection between the source code and the machine. While you can easily look into the include files to determine the real type of variables that are used in Windows programming, this can cause problems when you're attempting to move your code across platforms. Although it can be useful to know the size of a variable type for memory-use calculations, there is no good reason to use (and plenty of reasons not to use) the type definitions provided by windows.h.

The CALLBACK type definition specifies that this function is an external entry point into the EXE, necessary because Windows calls this procedure directly. On the desktop, CALLBACK indicates that the parameters will be put in a Pascal-like right-to-left push onto the program stack, which is the reverse of the standard C-language method. The reason for using the Pascal language stack frame for external entry points goes back to the very earliest days of Windows development. The use of a fixed-size, Pascal stack frame meant that the called procedure cleaned up the stack instead of leaving it for the caller to do. This reduced the code size of Windows and its bundled accessory programs sufficiently so that the early Microsoft developers thought it was a good move. Windows CE applications use a C stack frame for all functions, regardless of whether they are externally callable.

The first of the parameters passed to the window procedure is the window handle, which is useful when you need to define the specific instance of the window. The wMsg parameter indicates the message being sent to the window. This isn't the MSG structure used in the message loop in WinMain, but a simple, unsigned integer containing the message value. The remaining two parameters, wParam and lParam, are used to pass message-specific data to the window procedure. The names wParam and lParam come to us from the Win16 days, when wParam was a 16-bit value and lParam was a 32-bit value. In Windows CE, as in other Win32 operating systems, both the wParam and lParam parameters are 32 bits wide.

Hello3 has a traditional window procedure that consists of a switch statement that parses the wMsg message ID parameter. The switch statement for Hello3 contains two case statements, one to parse the WM_PAINT message and one for the WM_DESTROY message. This is about as simple as a window procedure can get.

WM_PAINT


Painting the window, and therefore processing the WM_PAINT message, is one of the critical functions of any Windows program. As a program processes the WM_PAINT message, the look of the window is achieved. Aside from painting the default background with the brush you specified when you registered the window class, Windows provides no help for processing this message. The lines of Hello3 that process the WM_PAINT messages are shown below here:

case WM_PAINT:
// Get the size of the client rectangle
GetClientRect (hWnd, &rect);
hdc = BeginPaint (hWnd, &ps);
DrawText (hdc, TEXT ("Hello Windows CE!"), -1, &rect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint (hWnd, &ps);
return 0;

Before the window can be drawn, the routine must determine its size. In a Windows program, a standard window is divided into two areas, the nonclient area and the client area. A window's title bar and its sizing border commonly make up the nonclient area of a window, and Windows is responsible for drawing it. The client area is the interior part of the window, and the application is responsible for drawing that. An application determines the size and location of the client area by calling the GetClientRect function. The function returns a RECT structure that contains left, top, right, and bottom elements that delineate the boundaries of the client rectangle. The advantage of the client vs. nonclient area concept is that an application doesn't have to account for drawing such standard elements of a window as the title bar.

Other versions of Windows supply a series of WM_NCxxx messages that enable your applications to take over the drawing of the nonclient area. In Windows CE, windows seldom have title bars. Because there's so little nonclient area, the Windows CE team decided not to send the nonclient messages to the window procedure.

All drawing performed in a WM_PAINT message must be enclosed by two functions, BeginPaint and EndPaint. The BeginPaint function returns an HDC, or handle to a device context. A device context is a logical representation of a physical display device such as a video screen or a printer. Windows programs never modify the display hardware directly. Instead, Windows isolates the program from the specifics of the hardware with, among other tools, device contexts.

BeginPaint also fills in a PAINTSTRUCT structure that contains a number of useful parameters:

typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;

The hdc field is the same handle that's returned by the BeginPaint function. The fErase field indicates whether the window procedure needs to redraw the background of the window. The rcPaint field is a RECT structure that defines the client area that needs repainting. Hello3 ignores this field and assumes that the entire client window needs repainting for every WM_PAINT message, but this field is quite handy when performance is an issue because only part of the window might need repainting. Windows actually prevents repainting outside the rcPaint rectangle, even when a program attempts to do so. The other fields in the structure, fRestore, fIncUpdate, and rgbReserved, are used internally by Windows and can be ignored by the application.

The only painting that takes place in Hello3 occurs in one line of text in the window. To do the painting, Hello3 calls the DrawText function. I cover the details of DrawText in Chapter 2, but if you look at the function it's probably obvious to you that this call draws the string "Hello Windows CE" on the window. After DrawText returns, EndPaint is called to inform Windows that the program has completed its update of the window.

Calling EndPaint also validates any area of the window you didn't paint. Windows keeps a list of areas of a window that are invalid (areas that need to be redrawn) and valid (areas that are up-to-date). By calling the BeginPaint and EndPaint pair, you tell Windows that you've taken care of any invalid areas in your window, whether or not you've actually drawn anything in the window. In fact, you must call BeginPaint and EndPaint, or validate the invalid areas of the window by other means, or Windows will simply continue to send WM_PAINT messages to the window until those invalid areas are validated.

WM_DESTROY


The other message processed by Hello3 is the WM_DESTROY message. The WM_DESTROY message is sent when a window is about to be destroyed. Because this window is the main window of the application, the application should terminate when the window is destroyed. To make this happen, the code processing the WM_DESTROY message calls PostQuitMessage. This function places a WM_QUIT message in the message queue. The one parameter of this function is the return code value that will be passed back to the application in the wParam parameter of the WM_QUIT message.

As I've mentioned, when the message loop sees a WM_QUIT message, it exits the loop. The WinMain function then calls TermInstance, which, in the case of Hello3, does nothing but return. WinMain then returns, terminating the program.

Hello3 is the classic Windows program. This programming style is sometimes call the Petzold method of Windows programming in homage to the ultimate guru of Windows programming, Charles Petzold. Charles's book Programming Microsoft Windows is currently in its fifth edition and is still the best book for learning Windows programming.

I prefer a somewhat different layout of my Windows programs. In a sense, it's simply a method of componentizing the function of a Windows program which, for me, makes it much easier to copy parts of one program to another. In the final example of this chapter, I introduce this programming style along with a few extra features that are necessary for Windows CE applications.

/ 169