Windows Overview (Windows Embedded CE 6.0)

1/6/2010

Windows are always rectangular. They are placed above and below each other along an imaginary line that runs perpendicular to the screen. This stack of windows is called the z-order. Each window has a unique position in the z-order. Windows that appear first in the z-order are considered to be in front of, or on top of, windows that appear later in the z-order. A window's position in the z-order affects its appearance; a window might obscure another window partially or totally, depending on its location, size, and position in the z-order.

A window can be displayed or hidden, depending on whether its WS_VISIBLE style is turned on or off, respectively. A window that has the WS_VISIBLE style turned off will not be displayed on the screen; a window that has the WS_VISIBLE style turned on might or might not be displayed on the screen, depending on whether it is obscured by other windows. Covering or uncovering a window by moving another window does not change the WS_VISIBLE style. However, using the ShowWindow API with the SW_SHOW flag makes the window visible, and using ShowWindow with the SW_HIDE flag hides the window.

Every window has a unique identifier that is known as a window handle. When you create a window, you receive a window handle, which you can use then to call functions that use the window.

The following code example shows how to create a window by using an hwndMain variable contains the window handle for the window.

HWND hwndMain = CreateWindow(szWindowClass, szTitle, WS_VISIBLE, 
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, 
NULL, hInstance, NULL);

Handles (HWND) are useful in applications that create multiple child windows. You can change attributes about the window handle by calling the SetWindowLong function, and you can retrieve the handle and attributes about the window by calling the GetWindowLong function.

A Windows-based application begins with a WinMain function. Every Windows Embedded CEā€“based application must have the WinMain function as its entry-point function. WinMain performs a number of tasks, including the following:

  • Registers a window definition for the main window by calling the RegisterClass function. This action is often referred to as "registering a window class."
  • Creates a main window by calling the CreateWindowEx function.
  • Enters a message loop where it waits for messages that signify events that are important for the main window to respond to.

WinMain does not need to register a window class or create a main window itself; WinMain can call other functions to perform these tasks.

One task that WinMain must perform itself is establishing a message loop. The message loop retrieves messages from a thread message queue and dispatches them to the appropriate window procedure. The message queue coordinates the transmission of messages for a specified thread. Each thread can have only one message queue. When a message is passed to a window, the message is placed on the message queue of the window thread. The thread receives and dispatches the message. There are two ways to pass a message to a window: posting a message and sending a message. Basically, the PostMessage function sends the message and returns immediately, while the SendMessage function waits for a response from the window to which the message was sent.

The following code examples show how to call PostMessage and SendMessage.

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

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

The following code example shows how to create a simple WinMain function by registering a window class, creating a main window, and entering a message loop.

int WINAPI WinMain(  HINSTANCE hInstance,HINSTANCE hPrevInstance,
                            LPTSTR lpCmdLine, int nCmdShow)
{
   TCHAR szTitle[] = TEXT("Window Title");      // The title bar text
   TCHAR szWindowClass[] = TEXT("Window Class");      // The window class name
   MSG msg;
   WNDCLASS wc; // The window class for this application

// Register the window class:
   
   wc.style           = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc    = (WNDPROC) WinProc; //The function to handle the window messages
   wc.cbClsExtra     = 0;
   wc.cbWndExtra     = 0;
   wc.hInstance      = hInstance;
   wc.hIcon          = 0;
   wc.hCursor        = 0;
   wc.hbrBackground  = (HBRUSH) GetStockObject(WHITE_BRUSH);
   wc.lpszMenuName   = 0;
   wc.lpszClassName  = szWindowClass;
   
   if (!RegisterClass(&wc)) return FALSE;//Failed to register the window
   
   // Create the main window
   
   HWND hwndMain = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  
   if (!hwndMain) return FALSE; //Failed to create the window
   
   ShowWindow(hwndMain, SW_SHOW); //Show the main window
   UpdateWindow(hwndMain); //Update or Redraw the main window
   
   // Loop here waiting for messages about the window 
   // until it is destroyed
   while (GetMessage(&msg, NULL, 0, 0)) 
   {
      TranslateMessage(&msg);
//This is the function that calls the main window WinProc with the 
//window messages
      DispatchMessage(&msg);
   }
   
   return msg.wParam;
}

Each window must be associated with a special function that is known as a window procedure or WinProc. Windows Embedded CE calls this window procedure to pass a message to the application.

The WinProc function is attached to a specific window class when the window class is registered. WinProc handles the messages (events) that are sent to all of the existing windows of that window class. WinProc is called in a loop to handle the events that are generated for that window, such as stylus taps and control actions.

A very basic implementation of WinProc consists of a switch statement that handles window messages or passes them on to the default system WinProc for the main window. So, the WinProc must have at least two elements:

  • A switch statement to handle the window messages, as required for the application.
  • A statement that sends the messages on to the default window procedure.

The following code example shows a typical implementation of WinProc.

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   HDC hdc;
   int wmId, wmEvent;

// The switch statement handles messages.
   switch (message) 
   {
      case WM_CREATE:
// Handle something before the window is created.
         break;

// Handle various windows messages.

      case WM_DESTROY:
         PostQuitMessage(0);
         break;
// The default window procedure 
      default:
         return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

A message consists of a message identifier and optional parameters. A message identifier is a named constant that identifies a message. In Windows Embedded CE, message identifiers typically are of the form WM_XXXXXXX, such as WM_COMMAND or WM_CREATE. When a window procedure receives a message, it uses a message identifier to determine how to process the message. For example:

  • The WM_CREATE message is sent to a window when the window is created.
  • The WM_DESTROY message is sent to a window when the window is destroyed.
  • The WM_PAINT message is sent to a window when the window client area has changed and must be repainted.

Message parameters contain data, or the location of data, that a window procedure uses to process messages. The meaning and value of the message parameters depend on the message identifier. A message parameter can contain an integer, packed bit flags, a pointer to a structure containing additional data, or other information. A window must check the message identifier to determine how to interpret the message parameters. The term "message" is used to mean either the message identifier or the identifier and the parameters together. The specific meaning usually is clear from the context.

The system sends a message to a window procedure by passing the message data as arguments to the procedure. The window procedure then performs an appropriate action for the message: it checks the message identifier and, while processing the message, uses data that is specified by the message parameters.

If a window procedure does not process a message, it should pass the message along for default processing. The window procedure does this by calling the DefWindowProc function, which performs a default action and returns a message result. The window procedure then must return this value as its own message result. Most window procedures process just a few messages and pass the others on to DefWindowProc.

Window procedures can be shared. The handle of the specific window that is receiving the message is available as an argument of the window procedure; it is the first parameter in the WinProc callback.

See Also

Concepts

Working with Windows and Messages

Other Resources

GWES Application Development