Chapter 6: Developing Phase: Migrating the User Interface

This chapter describes how to migrate from a UNIX-based user interface to a Microsoft® Windows® user interface. Because the majority of UNIX graphical interfaces are built on X Windows and Motif, the chapter focuses on porting code from X Windows to the Windows operating system.

This chapter describes:

  • The architectural and visual differences between the two environments.

  • The programming principles used by X Windows and Windows.

  • How to migrate each type of graphical construct from one environment to the other.

With this knowledge, you will be able to choose the most suitable methodology for migrating your applications from the UNIX user interface to the Windows user interface. You will also be able to map between X Windows UI routines and Windows UI routines in order to migrate X Windows applications.

*

On This Page

Comparing X Windows with Win32/Win64 GUI Comparing X Windows with Win32/Win64 GUI
User Interface Programming in X Windows and Microsoft Windows User Interface Programming in X Windows and Microsoft Windows
Libraries and Include Files Libraries and Include Files
Event Handling Event Handling
Graphics Device Interface Graphics Device Interface
Display and Color Management Display and Color Management
Windows Character Data Types Windows Character Data Types
Property Sheets Property Sheets
Toolbars Toolbars
Status Bars Status Bars
Printing Printing
Imaging Imaging
Mapping X Windows Terminology to Microsoft Windows Mapping X Windows Terminology to Microsoft Windows
Porting OpenGL Applications Porting OpenGL Applications

Comparing X Windows with Win32/Win64 GUI

This section describes the difference in architectures between X Windows and the Microsoft Win32®/Win64 GUI. The main user interface type in use on the UNIX platform today is built on the X Windows set of standards, protocols, and libraries. When migrating such a user interface, it is important to compare the user interface architecture and the resulting “look and feel” of the two models. It is also useful to understand the differences in user interface terminology between the two environments.

User Interface Architecture

The X Windows-based interfaces architecture differs from that of Windows. The first and most fundamental difference is the orientation of client and server. For X Windows, the client is the application that requests services and receives information from the user interface.

The user-facing elements of the interface are based on what is termed the X Server. In the X Windows-based system, the client application sends requests to the server to display graphics and to send mouse and keyboard events. The X Server is responsible for doing all the work on behalf of the client. The client can run on a remote system with no graphics hardware or on the same physical computer as the server. In either case, the client does not interact with the display, mouse, or keyboard. This is shown in Figure 6.1, which represents the X Windows client/server architecture.

Figure 6.1. The X Windows architectural model

Figure 6.1. The X Windows architectural model

The Windows environment is implemented as a client/server system. Applications are bound to the application programming interface (API) exported by the operating system by link-time binding.

The environment is the server and the Windows API programs are the clients. The Windows API application links to the client-side dynamic-link libraries (DLLs), such as GDI32.dll or user32.dll. When the application makes any Graphics Device Interface (GDI) function calls, the client-side GDI DLL will invoke the native system call in the kernel mode. This is because the GDI components reside in the kernel mode. This results in a switch from the user mode to kernel mode and does not require any kind of message passing and context switching, thereby improving performance.

Figure 6.2 illustrates the Windows architectural model.

Figure 6.2. The Microsoft Windows UI architectural model

Figure 6.2. The Microsoft Windows UI architectural model

Elements of the UI

Windows types are very similar in both the X Windows and Windows environments, as detailed as follows:

  • Application window. The application window is the interface between the user and the application. Elements such as a menu bar, status bar, window menu, minimize and maximize buttons, close button, title bar, sizing border, client area, and scroll bars typically appear in the application window.

  • Dialog boxes. A user typically accesses a dialog box as a temporary window used to create some additional input. A dialog box contains one or more controls, such as buttons and check boxes, to extract user input. Windows API programs can be entirely dialog-based just as in UNIX.

  • Controls. Controls such as X Windows widgets come in all shapes, sizes, colors, and functions. There are two ways to create controls in a Windows API environment. One is by using the resource editor, where you can drag and drop the controls from the tool bar onto the window because controls are also windows. The other method of creating a control is by using the CreateWindow API by specifying the required attributes.

  • Property sheets. Property sheets are tabbed dialog boxes. They can be used to select a number of settings for a particular application.

User Interface Programming in X Windows and Microsoft Windows

The basics of getting a Windows-based application and an X Windows/Motif-based application started are similar conceptually. Also, the libraries and core functions are similar in both environments. This section discusses the programming principles for developing user interfaces in the two environments. Using the information provided in this section, you will be able to choose the appropriate technology for migrating from the X Windows UI to the Windows UI and understand the Windows UI programming concepts.

Programming for Windows

When programming for Windows, you can use either the C style API or the C++ style API. As far as the C++ style API is concerned, the programming approach is object-oriented programming.

Note X Servers are available for Windows. These run Win32/Win64 unmanaged code programs. Third-party tools, such as MKS and Hummingbird XDK, are available to run X Windows applications in Win32.

To program in C++ on Windows, the following libraries are available:

  • Microsoft Foundation Classes (MFC)

  • Active Template Library (ATL)

  • GDI+

  • .NET Languages

Microsoft Foundation Classes (MFC)

In Visual C++®, Microsoft provides a class library called Microsoft Foundation Classes (MFC) with around 200 classes. The classes in MFC provide a wrapper around the Windows API, thereby providing the user with a set of object-oriented programming (OOP) tools for Windows programming. MFC encapsulates the Windows API. MFC provides various sets of classes for the following categories:

  • MFC application architecture classes

  • Window support classes

  • Drawing and printing classes

  • Simple datatype classes

  • Collection classes

  • File and database classes

  • Internet and networking classes

  • OLE Linking and Embedding classes

  • Debugging and exception classes

Active Template Library (ATL)

Active Template Library (ATL) is known primarily for its COM support. It also provides several classes that simplify Microsoft Windows programming. Like the rest of ATL, these classes are template-based C++ classes and have very low overhead. ATL can be used to create windows and dialog boxes and to handle messages.

GDI+

GDI+ is a class-based API for C/C++ programmers. It enables applications to use graphics and formatted text on video and on print. Windows API-based applications do not access graphics hardware directly. Instead, GDI+ interacts with device drivers on behalf of applications. GDI+ is also supported by the 64-bit Windows operating system.

To use GDI+, the developer must copy the Gdiplus.dll library to the system directory of the user’s computer. For information about the operating systems required in order to use a particular class or method, refer to the “Requirements” section of the documentation for the class or method.

All Windows-based applications can use GDI+, a new technology in the Microsoft Windows XP and Windows Server™ 2003 operating systems. It is also available for applications that run on older operating systems, such as Microsoft Windows NT® 4.0 SP6, Windows 98, Windows 2000, and Windows Millennium Edition operating systems.

Note You can download the latest redistributable at https://www.microsoft.com/downloads/search.aspx?displaylang=en.

.NET Languages

Microsoft .NET is the latest component-based development platform from Microsoft. From a high-level perspective, .NET facilitates component-based development in addition to radically extending the development platform and providing the tools and technologies that developers can use to develop a new kind of Internet-based distributed application.

Note For more information, refer to Volume 4, Migrate Using .NET of this guide.

Choosing the Programming Language

When developing components and applications, you can choose between any of the approaches described in this section.

  • Using ATL. ATL is a fast and easy way to create a COM component in C++ and to maintain a small footprint. ATL can be used to create a control that does not need all of the built-in functionality that MFC automatically provides.

  • Using MFC. MFC allows you to create full applications, ActiveX controls, and active documents. If you have created a control with MFC, you may want to continue development in MFC. When creating a new control, consider using ATL if you do not need all of the built-in functionality of MFC.

  • Using .NET languages. This is a good choice in situations where modules are being developed in different .NET languages and they need to communicate with each other without any marshalling, as is needed in the case of COM. For more information, refer to Volume 4, Migrate Using .NET of this guide.

In the remainder of this chapter, examples will be given in both the C style API as well as the C++ style API.

Programming Principles

The basic structure of an X Windows-based application that uses Motif is quite similar to the structure of a Windows-based application.

To initiate an X Windows-based interface

  1. Initialize the toolkit.

  2. Create widgets.

  3. Manage widgets.

  4. Set up callbacks.

  5. Display widgets.

  6. Enter the main program event handler.

The following code illustrates these steps:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

topWidget = XtVaAppInitialize();
frame = XtVaCreateManagedwidget("frame",
xmFrameWidgetFrams, topWidget,,,);
button = XmCreatePushButton( frame, "EXIT", NULL, 0 );
XtManageChild(button)
XtAddCallback( button, XmNactivateCallback, myCallback, NULL );
XtRealizeWidget( topWidget );
XtAppMainLoop();

To initiate a Microsoft Windows-based application

  1. Initialize an instance and register the Window class.

  2. Set up callbacks.

  3. Create the window.

  4. Display the window.

  5. Enter the main program message loop.

The following C style API code illustrates these steps:

windowClassStruct.hInstance = thisApplicationInstance;
windowClassStruct.lpfnWndProc = (WNDPROC)myCallback;
RegisterClass( &windowClassStruct );
myWindow = CreateWindow();
ShowWindow(myWindow);
while( GetMessage(,,,) ) {...}

X Windows clients and Windows API-based applications rely on events and messages from the outside to manage input devices. The X Windows and Windows APIs use a similar method for this: a message loop where a callback function or inline code executes based on the nature of the event or message.

The following code shows a simple Windows API message loop:

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

The GetMessage API returns an MSG structure (&msg). Right now, only the message member of this structure (UINT message in the following example) is of interest. Windows places the message identifier in this field. The developer can use this in the message loop to capture device events.

typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT py;
} MSG, *PMSG;

In ATL, the event handling is implemented with the MESSAGE MAP macros defined within a window class.

To make use of the message handling feature in the CWindowImpl ATL class

  1. Define a class CMyWindow derived from CWindowImpl.

  2. Define the Message Map.

  3. Define the member functions of CMyWindow that can handle the messages.

  4. Create an instance of CMyWindow class.

  5. Create the Window using the Createmember function of the CWindowImpl class.

    Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

    // Step1 Define the new class and the new 
    

// class's name must be passed as an // argument to the CWindowImpl template. class CMyWindow : public CWindowImpl<CMyWindow> { //Note //Step 2 Define the Message Map BEGIN_MSG_MAP(CMyWindow) // Implies that the OnPaint member function //will be invoked for the message WM_PAINT   MESSAGE_HANDLER(WM_PAINT,OnPaint)   MESSAGE_HANDLER(WM_CREATE,OnCreate)   MESSAGE_HANDLER(WM_DESTROY,OnDestroy) END_MSG_MAP() //Step3 Define the member functions that handle the messages: LRESULT OnPaint(   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { ... } LRESULT OnCreate(   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { ... } LRESULT OnDestroy(   UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { ... } }; // CMyWindow ...... //Step 4 Create an object of class CMyWindow CMyWindow wnd;   // constructs a CMyWindow object //Step5 Create a window on the screen wnd.Create( NULL, CWindow::rcDefault, _T("Hello"),   WS_OVERLAPPEDWINDOW|WS_VISIBLE );

Detailed information on message maps in ATL is available at
https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_atl_message_maps.asp.

Note   IA64
LPARAM, WPARAM, and LRESULT are the typical polymorphic types; they hold pointers or integral types. When returning data from wParam and lParam fields of the MSG type variable, do not assign these values to variables of data types DWORD, ULONG, UINT, INT, int, or long values.
In this case, the Win64 compiler will give the following warning:
Warning C4244: 'return': conversion from 'WPARAM' to 'int', possible loss of data

Creating Windows

The code examples in this section show X Windows and Windows API implementations of window management. It is not likely that any large-scale X Windows client or Windows API-based application would actually be implemented as these short code examples. However, it is easy to see the conceptual similarities and some differences as well.

An X Windows X11 client might use the XtAppInitialize, XtVaAppInitialize, 

XtOpenApplication , or XtVaOpenApplication function to get a top-level widget to create a window, as shown in the following example code.

main (int argc, char *argv[] )
{
Widget toplevel; /* Conceptual Application Window */
XtAppContext app; /* context of the app */
toplevel = XtVaAppInitialize( &app,
"myClassName",
NULL,0,&argc,argv,NULL,NULL );
OR
toplevel = XtOpenApplication( &app,
"myClassName",
NULL,0,&argc,argv,NULL,
whateverWidgetClass, NULL,0);
}

In the following code, a Windows API-based graphical application creates a main window.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASS wndclass;
   wndclass.style =         CS_HREDRAW | CS_VREDRAW;
   wndclass.lpfnWndProc =     WndProc;
   wndclass.hInstance =     hInstance;
   wndclass.hIcon =    LoadIcon(NULL,     IDI_APPLICATION);
   wndclass.hCursor =     LoadCursor(NULL, IDC_ARROW);
   wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
   wndclass.lpszMenuName = NULL;
   wndclass.lpszClassName = " myClassName ";
   RegisterClass(&wndclass);
HWND hWnd; // handle to the Application Window
hWnd = CreateWindow( "myClassName",
"myWindowsName",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
hInstance, // context of the app
NULL);

Note   IA64
When setting the cbWndExtra member of the WNDCLASS structure, be sure to reserve enough space for pointers.
User-exposed, named kernel objects such as HWND are 32 bits only. Ensure that explicit values of HANDLE are not used. For example, use INVALID_HANDLE_VALUE instead of 0xffffffff.

In ATL, the class CWindow can be used to create the window as shown in the following code.

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

CWindow win;
win.Create( "button", NULL, CWindow::
rcDefault, "Click me",
  WS_CHILD );
win.ShowWindow( nCmdShow );
win.UpdateWindow();
Common Dialog Boxes

The Common Dialog Box Library contains a set of dialog boxes for performing common tasks, such as opening files and printing documents. The common dialog boxes provide a uniform user interface that lets users carry out these common tasks in the same way for each application, which makes for a rapid migration of the UI.

The common dialog boxes include:

  • The Open and Save As file dialog boxes.

  • The Find and Replace editing dialog boxes.

  • The Print, Print Setup, Print Property Sheet, and Page Setup printing dialog boxes.

  • The Color and Font dialog boxes.

Note Additional information on the Common Dialog Box Library is available at https://msdn.microsoft.com/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/CommonDialogBoxLibrary.asp.

Creating Dialogs Boxes

The following section describes different types of dialog boxes and their implementation. Dialog boxes can be of either modal or modeless.

Modeless Dialog Box

When the system creates a modeless dialog box, it becomes the active window. The modeless dialog box does not disable its parent window or send messages to its parent window. However, it stays at the top of the z-order even if its parent window becomes the active window.

Applications can create a modeless dialog box by using the CreateDialog function, with arguments to specify the identifier of a dialog box template and the pointer to the callback procedure that handles messages for the window. The main characteristic of the modeless dialog boxes is that they allow the event loop of their parent to continue processing messages while they operate. For example, a progress dialog that displays progress indicators of processing done by the parent.

A modal dialog box becomes the active window when the system creates it. Until a call to EndDialog, the dialog box remains the active window. Neither the application nor the user can make the parent window active before calling EndDialog. An application uses the DialogBox function with a resource identifier to create a modal dialog box. Use a modal dialog box when it is desirable to force user input before proceeding. All common dialog boxes are modal except the Find and Replace dialog boxes.

A dialog box procedure is similar to a window procedure in that the system sends messages to the procedure when it has information to give or tasks to carry out. Unlike a window procedure, a dialog box procedure never calls the DefWindowProc function. Instead, it returns TRUE if it processes a message or FALSE if it does not.

The following is a sample dialog box procedure:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

INT_PTR CALLBACK MyDialogProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (wCommand)
{
case IDOK:
hList = GetDlgItem(hWnd, IDC_LISTNAMES);
GetDlgItemText(hWnd, IDC_TEXT, buffer, 10);
SendMessage(hList,LB_ADDSTRING,i_count,(LPARAM)
buffer);
MessageBox(hWnd, buffer, _T("Names"), MB_OK);
return TRUE;
}
case WM_CLOSE:
{
 EndDialog(hWnd, 0);
 return TRUE;
}
    return FALSE;
}

Note   IA64 
To prepare the code for Win64, the DialogBox Procedure return type must be INT_PTR. If the return type is BOOL, the compiler throws an error while creating the dialog. This is because, on the Windows API, the return types BOOL and INT_PTR are of the same size, whereas on Win64 the INT_PTR return type size is 64 bits.
If you use the LRESULT as the return type, both Win32 and Win64 display no warning because the LRESULT and LONG_PTR result types map to each other. The INT_PTR and LONG_PTR result types are of the same size on both x86 and Itanium.

The following CreateDialog function creates the dialog box and all the controls that it contains. Note that the second parameter is the name of the dialog box as it appears in the first line of the resource text.

/*
** Create modeless dialog box.
*/
hExampleDlg = CreateDialog( hInstance,
MAKEINTRESOURCE(IDD_DIALOG1),
(HWND)NULL,
MyDlgProc );

The following DialogBoxParam function creates a modal dialog box and all the controls that it contains, once again from a dialog box template resource.

/*
** Create modal dialog box.
*/
int value = 1;
DialogBoxParam(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG1), 
(HWND)NULL, 
MyDialogProc,
value);

Note   IA64
The last parameter of the DialogBoxParam function is an IN parameter that specifies the value to pass to the dialog box in the LPARAM parameter of the WM_INITDIALOG message.
It is acceptable to have an integer variable in place of LPARAM because the conversion does not result in any loss of data.

EndDialog must be invoked to destroy a modal dialog box, and DestroyWindow must be invoked to close a modeless dialog box. The following sample shows the usage of the DestroyWindow function.

  LRESULT OnClose( UINT, WPARAM, LPARAM, BOOL& )
    {
           DestroyWindow(); 
     return 0;
    }
 .....
};

In the case of ATL, you can create dialog boxes using the ATL class CDialogImpl.

The following C++ code example creates a dialog box by defining a new class CMyDialog derived from the ATL class CDialogImpl.

IDD_DIALOG1 is the dialog template resource identifier. WM_INITDIALOG is the event to be handled to perform any initialization before the dialog box is displayed. In the following code example, this is done in the event handler OnInitDialog, which is a member function of the CMyDialog class.

class CMyDialog: public CDialogImpl<CMyDialog>
{
public:
  enum { IDD = IDD_DIALOG1 };
  BEGIN_MSG_MAP( CMyDialog )
   MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
  END_MSG_MAP()
  LRESULT OnInitDialog( UINT, WPARAM, LPARAM, BOOL& )
  {
   //Initialize here
....
   return 0;
  }
  };

The CDialogImpl class can be used to create both modal as well as modeless dialog boxes. The following code illustrates how to display a modal dialog box:

STDMETHODIMP CMyApplication::InfoBoxModal()
{
  CMyDialog dlg;
  dlg.DoModal(); // Displays a modal Dialog box
  return S_OK;
}

The following code displays a modeless dialog using the Create member function, which takes as parameter the object representing the parent window.

int APIENTRY WinMain( HINSTANCE hInstance, 
HINSTANCE, LPSTR, int )
{
  _Module.Init( NULL, hInstance );
    CMyWindow wnd; 
      wnd.Create( NULL, CWindow::rcDefault, _T("Hello"),
           WS_OVERLAPPEDWINDOW|WS_VISIBLE );
     CMyDialog dlg1; 
    dlg1.Create(wnd);
// If the dialog box resource does not have the 
// WS_VISIBLE style invoke 
// ShowWindow
dlg1.ShowWindow( SW_SHOW ); 
}

The following code example uses the BEGIN_MSG_MAP message map macro. Message map associates a handler function with a particular message, command, or notification. By using message map macros of ATL, you can specify a message map for a window. The window procedures in CWindowImpl, CDialogImpl, and CContainedWindow direct messages form a window to its message map.

Note Additional information on message maps is available at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_atl_message_maps.asp.

class CMyDialog: public CDialogImpl<CMyDialog>
{
public:
  enum { IDD = IDD_DIALOG1 };
  BEGIN_MSG_MAP( CMyDialog )
   MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
     MESSAGE_HANDLER( WM_CLOSE, OnClose )
  END_MSG_MAP()
  ......
Creating Controls

Controls, such as X Windows widgets, come in all shapes, sizes, colors, and functions. There are two ways to create controls in a Windows API environment. The first and simplest method is by using one of the many dialog box editors. Use these tools to drag and drop controls onto a window or dialog box, which in X Windows is a widget itself. In the Windows API, controls are also windows in every respect. The second method is to call the CreateWindow function with the necessary parameters to produce the desired control at the desired location inside a parent window. This section describes the usage of X Windows widgets and Windows controls. An X Windows client can create a control or widget, as shown in the following example.

X Windows example: Display a control on parent window

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

main (int argc, char *argv[] )
{
Widget toplevel; /* Conceptual Application Window */
Widget button;
XtAppContext app; /* context of the app */
toplevel = XtVaAppInitialize( &app, "Example", 
NULL,0,&argc,argv,NULL,NULL );
button = XtVaCreateManagedWidget( "command", // button text
commandWidgetClass, //the type of widget
toplevel, // parent widow or parent widget
XtNheight, 50,
XtNwidth, 100,
XtNlabel, "Press To Exit",
NULL );
}

(Source File: U_CreateCtrl-UAMV3C6.01.c)

Following is a Windows example to display the control on a parent window.

Windows example: Display a control on parent window

HWND handleToThisButton;
handleToThisButton =
CreateWindow( "BUTTON", // the type of control
"Fire Phasers",// button text
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,// the button style
XpositionInParent,
yPositionInnParent,
BUTTONWIDTH,
BUTTONHEIGHT,
handleOfParentWindow,// parent window
(HMENU)NUMBER_USED_TO_ID_THIS_CONTROL,
hInst,
NULL );
Identifying a Control

To communicate with or respond to a control, it is necessary to identify it. This is done using the window handle and a unique ID associated with the control. You can use the handle to a control just as a handle to any window. For example, calling SetWindowPos with the window handle of the control can move the control or make it larger. Use the ID in the WindProc switch statement to send or capture messages to and from the control.

The following API calls use the ID of the control along with the handle of the parent window:

  • SetDlgItemText

  • GetDlgItemText

  • GetDlgItemInt

  • SetDlgItemInt

If the developer uses CreateWindow to build the control, both identification pieces—the ID of the control and the handle of the parent window—are known. CreateWindow returns the handle to the control, and the ninth parameter in the call to CreateWindow is the unique ID the application associates with that control.

Communicating with a Control

After the application identifies a control, it can communicate with it. The following are some examples of sending and receiving commands or messages from controls.

X Windows example: Sending and receiving commands or messages from control

// X11/Motif
//
XmString newString;
newString = XmStringCreateLocalized("String One");
XmListAddItem( listWidget, newString, 0);
XmStringFree(newString);
newString = XmStringCreateLocalized("String Two");
XmListAddItem( listWidget, newString, 0);
XmStringFree(newString);
newString = XmStringCreateLocalized("String Three");
XmListAddItem( listWidget, newString, 0);
XmStringFree(newString);

Windows example: Sending and receiving commands or messages from control

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

//+
// programmatically add strings to the list box , part 
// of the Dialog Procedure is given below
//-
// ATL 
//
class CMyDialog: public CDialogImpl<CMyDialog>
{
public:
  enum { IDD = IDD_DIALOG1 };
  BEGIN_MSG_MAP( CMyDialog )
      COMMAND_ID_HANDLER( IDOK, OnOK )
      COMMAND_ID_HANDLER( IDCANCEL, OnCancel)
   MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
     MESSAGE_HANDLER( WM_CLOSE, OnClose )
  END_MSG_MAP()
  LRESULT OnInitDialog( UINT, WPARAM, LPARAM, BOOL& )
  {
    // Get the handle to the ListBox 
    // control whose ID is IDC_LIST1
    hList = GetDlgItem(IDC_LIST1 ); 
i_count = 0;
   return 0;
  }
  LRESULT OnClose( UINT, WPARAM, LPARAM, BOOL& )
    {
      DestroyWindow();
      return 0;
    }
  LRESULT OnOK( UINT, WPARAM, HWND, BOOL& )
    {
        // Get the text from the Edit control whose ID is IDC_EDIT1
         GetDlgItemText( IDC_EDIT1 , str,20 );
        // Add items to the list box on clicking OK
         SendMessage(hList,LB_ADDSTRING,i_count,(LPARAM) str);
         i_count++;
         return 0;
    }
  LRESULT OnCancel( UINT, WPARAM, HWND, BOOL& )
    {
     //Close the Dialog on clicking Cancel     
      DestroyWindow();
      return 0;
    }
 TCHAR str[22];
 HWND hList;
 int i_count;
};

Note   SendMessage returns a LRESULT and takes as parameters HWND, an UINT, a WPARAM, and an LPARAM.
The WPARAM and LPARAM data types have been tailored for the appropriate operating systems such that they are 32 bits on a 32-bit target operating system and 64 bits on a 64-bit platform.
So when passing an LPARAM-type value as the fourth parameter, the cast, if any, should be done to LPARAM and not to DWORD so that the code is 64-bit compliant.

In the case of ATL, we can set the focus to a particular control on the dialog by first attaching the child control to a Window handle and then invoking SetFocus, as shown in the code of an event handler.

// Windows ATL
LRESULT OnFocusListBox( UINT, WPARAM, HWND, BOOL& )
    { 
      CWindow hWnd;
        hWnd.Attach(hList);
        hWnd.SetFocus();
        return 0;
    }

In the case of a modeless dialog box, to ensure that the TAB key and mnemonics work properly, a call to IsDialogMessage must be made in the main message loop of the application as shown. For more information on IsDialogMessage, refer to MSDN®.

while( GetMessage( &msg, NULL, 0, 0 ) )
{
      if ( dlg1 ==NULL || !IsDialogMessage(dlg1, &msg) )
      {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
      }
} 

Table 6.1 describes X Windows and Windows routines for setting focus and selecting the list box item.

Table 6.1. X Windows and Windows Routines

X Windows

Windows

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

XSetInputFocus(Display display, Window focus, 
int RevertToParent, Time timeNow)
HWND SetFocus( HWND hwnd )

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

XmListSelectPos(Widget listWidget, 
int position, Boolean notify)
LRESULT SendMessage(HWND hwnd, UINT 
message,WPARAM wParam,LPARAM lParam )

Libraries and Include Files

Despite differences in their underlying architectures, many of the graphical functions used in X Windows and Windows perform similar tasks. These include the core libraries and the Motif and Windows API common dialog boxes. You can identify the necessary header files and libraries to port UNIX/Motif core GUI components and common dialogs to the Windows UI.

Core Libraries

A number of functions exist to support the core API used in a graphical user interface. X Windows includes the libraries X and Xlib and the X Windows Intrinsics toolkit. The Windows API equivalent is Windows.h, which includes a large number of additional header files.

The Microsoft compiler includes Windows API USER32.LIB and GDI32.LIB import libraries, which can be roughly compared to X Library and X Toolkit Intrinsics because they provide nearly all of the basic window management and 2-D graphics APIs. These Windows API libraries are called import libraries because they provide information to the linker. When a Windows API-based program references the CreateWindow function, User32.lib tells the linker that this function is in the User32.dll dynamic-link library. This information goes to the .exe file, which enables Windows to perform dynamic linking by using the User32.dll and Gdi32.dll DLLs when the program is executed.

Motif and Windows API Common Dialog Boxes

Dialog box functionality is provided by Motif and by the Windows Common Dialog Box Library. If the code migrates from Motif, there is probably an equivalent Windows API common dialog box for each Motif function.

Windows API provides a set of functions to create commonly used windows. If Commdlg.h is included in a project, the project has access to the Windows API common dialog box functions. The Comdlg32.dll library stores templates for these dialog boxes, along with the code to drive them. By using these, a developer can save time and provide a consistent look and feel in the application being migrated.

For example, the Motif function XmCreateFileSelectionDialog is very similar to the Windows API function GetOpenFileName. The X/Motif code must include the Xm/ FileSB.h header file. The Windows API-based application must include Commdlg.h and must link to Comdlg32.lib. Calling the GetOpenFileName API displays the Open File dialog box.

In addition to Windows.h, the Windowsx.h library has roots in Windows version 3.1 and provides many useful macros that can be used in code migration. These macros are not used as often or in the same ways now, but they can be helpful. For example, using the SelectPen and DeletePen macros can be more intuitive than calling SelectObject and DeleteObject with all the required type specifications:

Note: The line has been split into multiple lines for readability.However, while trying it out on a system you must enter it as one line without breaks.

#define SelectPen(hdc, hpen)((HPEN)
SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
#define DeletePen(hpen) DeleteObject((HGDIOBJ)
(HPEN)(hpen))

Event Handling

This section describes the X Windows and Windows mouse and key board event handling messages. You can use this information to identify the suitable windows routines for the existing X Windows mouse and keyboard event handling routines.

Capturing Mouse Events

There are more than 30 mouse input messages, divided into two cases:

  • Client-area mouse messages

  • Nonclient-area mouse messages

A window receives client-area mouse messages when a mouse event occurs in the client area of that window. The file Winuser.h (included by Windows.h) defines these message values, as listed in Table 6.2.

Table 6.2. Mouse Event Definitions

Message

Event

WM_LBUTTONDBLCLK

The left mouse button was double-clicked.

WM_LBUTTONDOWN

The left mouse button was pressed.

WM_LBUTTONUP

The left mouse button was released.

WM_MBUTTONDBLCLK

The middle mouse button was double-clicked.

WM_MBUTTONDOWN

The middle mouse button was pressed.

WM_MBUTTONUP

The middle mouse button was released.

WM_RBUTTONDBLCLK

The right mouse button was double-clicked.

WM_RBUTTONDOWN

The right mouse button was pressed.

WM_RBUTTONUP

The right mouse button was released.

WM_XBUTTONDBLCLK

Windows 2000 or Windows XP: An X mouse button was double-clicked.

WM_XBUTTONDOWN

Windows 2000 or Windows XP: An X mouse button was pressed.

WM_XBUTTONUP

Windows 2000 or Windows XP: An X mouse button was released.

Client and Nonclient-Area Mouse Messages    

A window receives client-area mouse messages when a mouse event occurs within the client area and nonclient-area mouse messages when a mouse event occurs in the window outside the client area. The nonclient area includes the border, title bar, scroll bar, menu, and minimize and maximize buttons. Each client area message has a corresponding nonclient-area message. A nonclient-area message is defined by including NC in its name, for example, WM_NCLBUTTONUP.

The lParam member of the MSG structure consists of two SHORT values representing the POINTS structure shown in the following code. This can give the current location of the mouse pointer. For client-area messages, the (x,y) pair is relative to the client area of the window. For nonclient-area messages, the (x,y) pair is relative to the upper-left corner of the screen.

The following code shows the handler for the message WM_LBUTTONDOWN that represents client-area mouse messages. The handler determines the (x,y) coordinates of the mouse pointer. (This example shows only the code relevant to the handler.)

Windows example: Handling mouse messages

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

BEGIN_MSG_MAP( CMyDialog )
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_NCLBUTTONUP, OnNCLButtonUP)
END_MSG_MAP()
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bVal)
    {
        POINT pnt;
        pnt.x = LOWORD(lParam);
        pnt.y = HIWORD(lParam);
        return 0;
    }
LRESULT OnNCLButtonUP(UINT uMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bVal)
    {
        MessageBox("Non Client Area : 
        Mouse Button UP");
        return 0;
    }

The process for handling client-area mouse messages in X11 is very similar, as shown in the following code.

X Windows example: Handling mouse messages

void main() {
Display *xdisplay;
XEvent xEvent;
int mouseX;
int mousey;
while (1) {
/* wait for next event */
XNextEvent (xdisplay, &xevent);
switch (xevent.type) {
case ButtonPress:
mouseX = xevent.xbutton.x;
mousey = xevent.xbutton.y;
break;
}
}

Capturing Keyboard Events

In UNIX, a KeyPress event is generated when the user presses a key on the keyboard. Similarly, a KeyRelease event is generated when the user releases the pressed key. Both events arrive with the XKeyEvent structure. A KeySym is a portable number to identify a key with a given engraving. The Xlib function, XLookupString, converts a KeyPress event into both a KeySym and an ASCII string. After you have a KeySym, you can deal with the key itself. The Xlib function XKeysymToString returns the string name for a given KeySym. The following example illustrates how these functions are used in capturing the keyboard events in UNIX.

X Windows example: Process keyboard events

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

void PrintKeyEvent(XKeyEvent* event)
{
    KeySym keysym;
    XComposeStatus compose_status;
    int length;
    char string[10];
    switch(event->type)
    {
        case KeyPress:
            printf("KeyPress ");break;
        case KeyRelease:
            printf("KeyRelease ");break;
        default:
            printf("not a key event \n");
            return;
    }
    length = XLookupString(event,string,9,
    &keysym,&compose_status);
    if((length > 0) && (length <=9))
    {
        string[length]='\0';
        printf("result of xlookupstring [%s] ", string);
    }
    printf("keysym [%s] \n", XKeysymToString(keysym));
}

In Windows, a scan code identifies each physical key on the keyboard. The device driver responsible for servicing the keyboard maps this number to a virtual-key code. The include file Winuser.h defines these virtual key codes. After mapping the scan code, the system places a message that includes the scan code and virtual key code along with other information in the system message queue. Some additional system processing takes place, and then the system sends the keyboard message to the process that has the keyboard focus.

Pressing a key causes a WM_KEYDOWN or WM_SYSKEYDOWN message to be placed in the thread message queue attached to the window that has the keyboard focus. Releasing a key causes a WM_KEYUP or WM_SYSKEYUP message to be placed in the queue.

The system posts a WM_CHAR message to the window with the keyboard focus when the TranslateMessage function translates a WM_KEYDOWN message. The WM_CHAR message contains the character code of the key that was pressed.

The following example shows how to manually catch and process keystrokes.

Windows example: Process keyboard events

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

//+
// contrived union used only to show how the bits of the
// lParam parameter are arranged
// when handling WM_KEYDOWN messages
//-
typedef union {
struct {
unsigned long repeatCount :16;
unsigned long scanCode :8;
unsigned long extendedChar :1;
unsigned long reserved :4;
unsigned long altKeyDown :1;
unsigned long previousState :1;
unsigned long transition :1;
}bits;
LPARAM lParam;
}tyKeyData;
BEGIN_MSG_MAP( CMyDialog )
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
MESSAGE_HANDLER(WM_CHAR, OnChar)
END_MSG_MAP()
//+
// ATL WM_KEYDOWN event handler
//-
LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
{
tyKeyData keyData;
TCHAR characterCode;
//+
// just for clarity showing what is in
// the wParam parameter when WM_KEYDOWN is
// sent to the window proc
//-
characterCode = ((TCHAR)(wParam));
//+
// the tyKeyData union is defined above
// this union displays how the bits are defined
//-
keyData.lParam = lParam;
if ( keyData.bits.altKeyDown ) {
//+
// using the keyboard hardware scan code
// to determine what key was pressed
//-
switch ( keyData.bits.scanCode ) {
case 0x3B : // <Alt-F1>
break;
case 0x3C : // <Alt-F2>
break;
default :
break;
}
}
else {
//+
// VK_XX Key Codes are found in winuser.h
// These are not the keyboard hardware scan codes!!!
// using the wParam to determine
// what key was pressed
//-
switch ( characterCode ) {
case VK_F1 : // <F1>
break;
case VK_F2 : // <F2>
break;
default :
break;
}
}
return 0;
}
LRESULT OnChar(UINT uMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
{
  characterCode = ((TCHAR)(wParam));
switch ( characterCode ) {
//+
// VK_XX codes can be used here
// VK_XX Key Codes are found in winuser.h
//-
case 0x08: // backspace
case 0x0A: // linefeed
case 0x1B: // escape
break;
case VK_LEFT : // left arrow
case VK_UP : // up arrow
case VK_INSERT : // the insert key
break;
//+
// convert TAB to Spaces
//-
case 0x09: // tab
for ( int i = 0; i < 4; i++)
SendMessage(hWnd, WM_CHAR, 0x20, 0);
}
return 0;
}
Keyboard Focus

Keyboard focus is a temporary property of a window or widget. At any given time, only one component can listen to the keyboard for events. The window or widget that is listening is said to have the current focus, keyboard focus, or just focus. Processing focus in a Windows API-based application involves processing the WM_KILLFOCUS and WM_SETFOCUS Windows messages. This is similar to using XmNfocusCallback and XmNlosingFocusCallback for focus callbacks set up within X/Motif.

The following code shows the window procedure for a subclassed button that is handling focus messages:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

LRESULT CALLBACK CSoftKeyProc
(HWND hWnd,UINT iMsg, WPARAM wParam,LPARAM lParam)
{
LRESULT lResult = FALSE;
//+
// this is a trick to retrieve data (in this case a pointer )
// that is attached to this window object.
// SetWindowLongPtr() was used to initially attach 
// this data to the window.
//The reason for this
// being used here is that this function may be the 
// callback for any number of these type
// objects and this data is "state" for this particular instance
//-
CvtSoftKey *pSoftKey = (CvtSoftKey *)GetWindowLongPtr( hWnd, 0 );
switch (iMsg) {
default :
break;
//+
// this window (button in this case) is receiving the focus
// so we can do whatever processing we like
// Draw a new border – Highlight the text – whatever!
//-
case WM_SETFOCUS :
lResult = pSoftKey->OnSetFocus( hWnd,iMsg,wParam,lParam);
break;
//+
// this window ( button in this case ) is losing focus
//-
case WM_KILLFOCUS :
lResult = pSoftKey->OnKillFocus( hWnd,iMsg,wParam,lParam);
break;
}
return DefWindowProc(hWnd,iMsg,wParam,lParam);
}

Note If a pointer or a handle is being retrieved, the GetWindowLongPtr function supersedes the GetWindowLong function. (Pointers and handles are 32 bits on 32-bit Windows and 64 bits on 64-bit Windows.) To write code that is compatible with both 32-bit and 64-bit versions of Windows, use GetWindowLongPtr.

Creating Keystrokes, Mouse Motions, and Button Click

You can simulate keystrokes, mouse motions, or button clicks by using the SendInput function to serially insert events into the mouse or keyboard stream.

Note Additional information about handling the keyboard is available at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/keybd_event.asp.

Graphics Device Interface

The Graphics Device Interface (GDI) is a set of API functions and data structures that can be used to generate graphics for devices such as displays and printers. These functions help you in creating such graphic objects as Pens, Brush, and Palette to draw such shapes as lines, circles, and rectangles. Functions are available to display the text of different fonts and to draw images as well.

This section describes the GDI-specific routines and functions used in X Windows applications and their corresponding replacements in the Windows environment. You can use this information to identify the best approach to migrate the GDI-specific routines in your UNIX application to the Windows environment using the Win32/Win64 API.

Device Context

Applications on both platforms use a context to control how drawing functions behave. On X Windows systems, this context is known as the graphics context (GC). On Windows API-based GDI systems, this context is known as the device context (DC). One difference between the two platforms is in the location where the operating system stores and manages drawing attributes such as the width of lines or the current font.

In X Windows, these values belong to the graphics context. When using XCreateGC or XtGetGC, it is necessary to provide a values mask and values structure. These values are used to store settings such as line width, foreground color, background color, and font style.

The following code is an example of the process of setting the foreground and background colors:

GC gcRedBlue;
XGCValues gcValues;
unsigned long gcColorRed;
unsigned long gcColorBlue;
unsigned long gcColorWhite;
Widget myWidget;
int main (int args, char **argv)
{
// initialize colors - widget - etc.
gcValues.foreground = gcColorRed;
gcValues.background = gcColorBlue;
gcRedBlue = XtGetGC ( myWidget, GCForeground 
| GCBackground, &gcValues);
}

Windows API-based applications use a different approach. The device context is a structure that defines a set of graphic objects and their associated attributes and the graphic modes that affect output. To keep this simple, the graphic objects include a font for displaying text, a pen for line drawing, and a brush for painting and filling. To draw lines, rectangles, and text, it is necessary to get or create one of these objects and select it into the desired device context.

Instead of creating several specialized graphics context objects as X Windows does, Windows API-based applications create several drawing objects and then select them into the device context as and when required. This methodology is similar to what an X Windows client application could do by getting a single graphics context and then repeatedly calling XChangeGC. The following code shows a Windows API-based application that creates several pens and uses them to draw lines and rectangles; the same code could be called from an event handler member function in the case of ATL classes:

#define onePixel 1
#define threePixels 3
#define thinLine onePixel
#define thickLine threePixels
COLORREF colorRed;
COLORREF colorBlue;
void drawSomthing( HDC hDC )
{
HPEN thinRedPen;
HPEN thinBluePen;
HPEN oldPen;
int x;
int y;
// initialize colors - etc.
//+
// create two pens.
// this could be done more statically somewhere so that
// it would not be necessary to create them each time
// this method is called.
//-
colorRed = RGB(255,0,0);
colorBlue = RGB(0,0,255);
thinRedPen = CreatePen( PS_SOLID, thinLine, colorRed );
thinBluePen = CreatePen( PS_SOLID, thinLine, colorBlue );
x = 100;
y = 200;
//+
// draw a line with the current pen,
// whatever it is at this time for this DC
//-
LineTo( hDC, x,y );
//+
// make our pen the current pen for the DC
// and save the existing one so we can put it back
//-
oldPen = (HPEN)SelectObject( hDC, thinRedPen );
//+
// draw a line with our pen
//-
LineTo( hDC, x,y );
//+
// make our other pen current in the DC.
// we are not saving the old one.
//-
SelectObject ( hDC, thinBluePen );
//+
// draw a line using our second pen
//-
LineTo( hDC, x, y );
//+
// put back the original pen
//-
SelectObject( hDC, oldPen );
//+
// get rid of our pen resources
//-
DeleteObject( thinRedPen );
DeleteObject( thinBluePen );
}

Getting Windows GDI Device Context

Windows API-based applications can retrieve the device context from the window handle, as shown in the following example:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

void myFunction ( HWND hWnd )
{
//+
// The following example attaches the Window handle
// hWnd to the CWindow object
// and calls CWindow::GetDC to retrieve the DC of the client
// area of the window wrapped by CWindow Object. 
//-
CWindow myWindow;
myWindow.Attach(hWnd); 
HDC hDC = myWindow.GetDC();// draw using the device context hDC
//+
// release the DC
//-
myWindow.ReleaseDC(hDC);
hDC = NULL;

Windows API-based applications can also retrieve the device context from the window handle by using BeginPaint and EndPaint, as shown in the following example:

LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
switch ( message ) {
case WM_PAINT:
//+
// Retrieve the device context (DC)
// for the window referenced by hWnd
//-
hDC = BeginPaint( hWnd, &ps );
//+
// draw with hDC or ps.hdc
//-
//+
// always follow BeginPaint() with EndPaint()
//-
EndPaint( hWnd, &ps );
break;
}
}

Creating Windows API GDI Device Context

It is often useful to draw in an off-screen buffer and then move that buffer into the display memory. This hides the live drawing function calls from the user and eliminates flicker in the window. This technique is called double buffering and is used extensively for programming games.

To create this off-screen context

  1. Calculate the width and height that are needed.

  2. Get the device context of the target (dialog box, button, or any other window object).

  3. Call CreateCompatibleDC.

  4. Call CreateCompatibleBitmap.

    // m_hButton is the window handle to a button.
    

// m_clientRect is a RECT structure. // Step 1. Calculate the size. GetClientRect( m_hButton, &m_clientRect ); m_width = ((int)( m_clientRect.right - m_clientRect.left )); m_height = ((int)( m_clientRect.bottom - m_clientRect.top )); // Step 2. Get the DC of the target window. hdc = GetDC( m_hButton ); // Step 3. Create a compatible device context. m_hdcMem = CreateCompatibleDC(hdc); // Step 4. Create a compatible bitmap - our X Windows drawable. m_hbmpMem = CreateCompatibleBitmap( hdc,m_width,m_height );

To use and display this off-screen bitmap

  1. Select the compatible bitmap into the compatible device context.

  2. Draw on that device context.

  3. Get the target window device context.

  4. Transfer the compatible memory image to the screen.

  5. Select the old bitmap into the device context.

    // Step 1. Select the compatible bitmap into the compatible DC.
    

// hbmpOld is a handle to a bitmap // m_hdcMem is the compatible device context // m_hbmpMem is the compatible bitmap hbmpOld = (HBITMAP)SelectObject( m_hdcMem, m_hbmpMem ); // Step 2. Draw on that DC. // FillRect() cleans out the rectangle FillRect( m_hdcMem, &m_clientRect, hBackgroundBrush ); // Draw a line LineTo( m_hdcMem, x,y ); // Step 3. Get the target DC. targetDC = GetDC( hTargetWindow ); // Step 4. Transfer the compatible image to the screen. // transfer everything to the screen // hdcMem is what we drew on //- BitBlt( targetDC, 0, 0, m_width, m_height, m_hdcMem, 0, 0, SRCCOPY ); // Step 5. Put the old bitmap back into the compatible DC. SelectObject( m_hdcMem, hbmpOld ); // based on program logic - Release the DC of the target window ReleaseDC( hTargetWindow, targetDC );

For more information about Windows API-based GDI device context, search the MSDN Web site for GetDC, CreateDC, CreateCompatibleDC, and DeleteDC.

Display and Color Management

The X Windows and Windows API-based GDI are both constrained by the physical limitations of the available display hardware. One such limitation is the number of colors a display adapter is capable of showing. You can use the information provided in this section to identify the corresponding Windows routines for Drawing and Graphics Device management. You will also be able to port X Windows applications with drawing and graphics code to the Windows environment.

All X Windows applications use a color map. This map can be shared or private. A shared color map is used by all other applications that do not use a private map. Using a private map gives an application better color control and potentially a greater number of colors. There is one problem with private maps: When the mouse moves on or off the client that is using a private map, the screen colors change. Windows API-based applications typically use color with no regard for the display device.

If the application uses a color that is beyond the capabilities of the display device, the system approximates that color within the limits of the hardware. On display devices that support a color palette, applications sensitive to color quality can create and manage one or more logical palettes.

A palette is similar to an X Windows color map. Both of these methodologies are used to map some desired colors onto the physical capabilities of the display hardware. For example, if a Windows API-based program needs more than 16 colors and is running on an 8-bits-per-pixel (bpp) display adapter, the program must create and use a palette.

The Windows API system palette can be thought of as being similar to an X Windows shared color map. A logical palette created and realized by an application can be thought of as an X Windows private color map.

A Windows API-based application that uses a logical palette exhibits some of the same behaviors as an X Windows application that uses a private color map. The application that gets priority in color selection is the one with the current focus. When the application that has the current focus calls RealizePalette, the system palette changes and the WM_PALETTECHANGED message is sent to all top-level and overlapped windows. This message enables a window that uses a color palette but does not have the keyboard focus to realize its logical palette and update its client area. The wParam parameter identifies the owner window. Inspecting this value prevents the originating window from realizing a logical palette repeatedly upon receipt of this message.

Today, most display hardware is capable of 24-bit or better color depth. For palette examples, see the many samples both on the MSDN Web site and in the Microsoft Windows Platform SDK.

To create a logical color palette

  1. Allocate a LOGPALETTE structure and assign values to it.

  2. Call CreatePalette with a pointer to the LOGPALETTE structure.

  3. Call SelectPalette by using the pointer returned from CreatePalette.

  4. Call RealizePalette to make the system palette the same as the device context.

  5. Call UnrealizeObject when finished with the palette.

To determine the capabilities of the hardware and to calculate the best possible behaviors of the display, an X Windows program can use such functions as:

  • DefaultColorMap

  • DefaultVisual

  • DisplayCells

  • DisplayPlanes

  • XGetVisualInfo

  • XGetWindowAttributes

A Windows API-based application can rely on GetDeviceCaps for this information. The GetDeviceCaps function retrieves device-specific information for the specified device. The following code example shows a few examples of device information that can be retrieved by using GetDeviceCaps. For a full list of the possible values of the nIndex parameter, refer to the operating system Help or search the MSDN Web site.

int GetDeviceCaps(
HDC hdc, // handle to DC
int nIndex // index of capability
);
void myFunction( HWND hThisWindow )
{
HDC hDC;
hDC = GetDC( hThisWindow );
widthOfScreenInPixels = GetDeviceCaps( hDC, HORZRES );
numberOfColorPlanes = GetDeviceCaps( hDC, PLANES );
numberOfColors = GetDeviceCaps( hDC, NUMCOLORS );
numberOfFonts = GetDeviceCaps( hDC, NUMFONTS );
}

Drawing 2-D Lines and Shapes

The device context of a drawing surface contains attributes that directly affect how lines, curves, and rectangles are drawn. These attributes include the current brush and pen and the current position.

The default current position for any given device context is (0,0) in logical two-dimensional (2-D) space. The value of the current position can be changed by calling MoveToEx, as shown in the following code example. The MoveToEx function updates the current position to the specified point and optionally returns the previous position. This function affects all drawing functions.

BOOL MoveToEx(
HDC hdc, // handle to device context
int X, // x-coordinate of new current position
int Y, // y-coordinate of new current position
LPPOINT lpPoint // old current position
);

The POINT structure defines the x and y coordinates of a point, as shown in the following code example:

typedef struct tagPOINT {
LONG x;
LONG y;
} POINT, *PPOINT;
Drawing Lines

Two sets of line and curve drawing functions are provided in the Windows API and GDI API. These two sets of functions are identified by the letters “To” at the end of the function name. Functions ending with “To” use and set the current position. Those functions that do not end with “To” leave the current position as it was. The LineTo function draws a line from the current position up to, but not including, the specified point, as shown in the following code example:

BOOL LineTo(
HDC hdc, // device context handle
int nXEnd, // x-coordinate of ending point
int nYEnd // y-coordinate of ending point
);

The PolylineTo function draws one or more straight lines that use and update the current position. A line is drawn from the current position to the first point specified by the lppt parameter by using the current pen. For each additional line, the function draws from the ending point of the previous line to the next point specified by lppt, as shown in the following code example:

BOOL PolylineTo(
HDC hdc, // handle to device context
CONST POINT *lppt, // array of points
DWORD cCount // number of points in array
);

The Polyline function draws a series of line segments by connecting the points in the specified array, as shown in the following code example. The lines are drawn from the first point through subsequent points by using the current pen. Unlike the LineTo or PolylineTo functions, the Polyline function neither uses nor updates the current position.

BOOL Polyline(
HDC hdc, // handle to device context
CONST POINT *lppt, // array of endpoints
int cPoints // number of points in array
);

X Windows example: Drawing lines

The following X Windows example shows the use of XDrawLine.

int main (int argc, char **argv)
{
XtToolkitInitialize ();
myApplication = XtCreateApplicationContext ();
myDisplay = XtOpenDisplay( myApplication,
NULL,
NULL,
"XBlaat",
NULL,
0,
&argc,
argv);
myWindow = RootWindowOfScreen(DefaultScreenOfDisplay (mydisplay));
//+
// now we need a surface to draw on
//-
myMap = XCreatePixmap ( myDisplay,myWindow,64,64, 1 );
values.foreground =
BlackPixel (myDisplay, DefaultScreen (myDisplay));
myGC = XCreateGC (myDisplay, mySurface, GCForeground, &values);
//+
// draw two diagonal lines across the 64x64 surface
//
XDrawLine( myDisplay,mySurface,myGC,0,0,63,63 );
XDrawLine( myDisplay,mySurface,myGC,0,63,63,0 );
...
}

Windows example: Drawing lines

The following Windows ATL example shows the use of MoveToEx and LineTo.

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

BEGIN_MSG_MAP( CMyWindow )
     MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
     MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
     MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
END_MSG_MAP()
POINTS current;
POINTS start;
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, 
LPARAM lParam, BOOL& bHandled)
{
COLORREF red = RGB(255,0,0);
// retrieve the current position from lParam
current.x = LOWORD(lParam);
current.y = HIWORD(lParam);
//Obtain the current device context
HDC hdc = GetDC();
//Create the red pen
HPEN pen = CreatePen(PS_SOLID, 2, red);
//Save the oldpen
HPEN oldpen = (HPEN)SelectObject(hdc, pen);
if (start.x != -1 )
{
//Move to the starting point selected in MouseUp event
     MoveToEx(hdc, start.x, start.y, NULL);
//Draw a line from the previous point to the current point
     LineTo(hdc, current.x, current.y);
     start.x = current.x;
     start.y = current.y;
}
}
Drawing Rectangles

In the Windows API, a rectangle shape is a filled shape. Filled shapes are geometric forms that the current pen can outline and the current brush can fill.

Following are the five filled shapes:

  • Ellipse

  • Chord

  • Pie

  • Polygon

  • Rectangle

In X Windows, the XRectangle shape is quite different from the Windows API equivalent. When porting between the two, it is necessary to understand the conceptual difference.

The X Windows version uses an upper-left–corner point and the width and height. The Windows API version uses the upper-left and lower-right points. This difference is also true for the XDrawRectangle and Windows API Rectangle functions.

The X Windows structure is as follows:

typedef struct {
short x,y;
unsigned short width,height;
} XRectangle;

Its Windows API equivalent is as follows:

typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;

The Rectangle function draws a rectangle and is outlined by using the current pen and filled by using the current brush. Because it does not fill the rectangle, this function is quite different from the XDrawRectangle function.

BOOL Rectangle(
HDC hdc, // handle to DC
int nLeftRect, // x-coord of upper-left corner of rectangle
int nTopRect, // y-coord of upper-left corner of rectangle
int nRightRect, // x-coord of lower-right corner of rectangle
int nBottomRect // y-coord of lower-right corner of rectangle
);

Rectangle functions that fill the rectangle are as follows:

  • X Windows: XFillRectangle

  • Windows API: Rectangle

  • Windows API: FillRect

Rectangle functions that draw the outline only are as follows:

  • X Windows: XDrawRectangle

  • Windows API: FrameRect

Note The Windows API functions Rectangle and FillRect differ in the parameters they take. For more information, refer to the Visual Studio® Help or the MSDN Web site.

<pre IsFakePre="true" xmlns="https://www.w3.org/1999/xhtml">X Windows example: Handling rectangle functions</pre>

The following X Windows example demonstrates rectangle functions:

void drawSomeRectangles()
{
//+
// fill the rectangle and then draw a black border around it
//-
XFillRectangle (myDisplay, mySurface, myWhiteGC, 0, 0, 31, 31);
XDrawRectangle (myDisplay, mySurface, myBlackGC, 0, 0, 31, 31);
//+
// draw an empty rectangle ten pixels square
//-
XDrawRectangle( myDislay, mySurface, myBlackGC, 0,0, 10,10 );
}

Windows example: Handling rectangle functions

The following ATL code example demonstrates rectangle functions on the Mouse left button down event:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled){ RECT myRectangle;
//+
// fill the rectangle and then draw a black border around it
// assume that the current pen in this DC is black and the
// current brush selected is red
// The rectangle top left corner is the point where
// the left mouse button 
// is clicked 
//-
HBRUSH myredBrush = CreateSolidBrush(RGB(255, 0, 0));
SelectObject(hdc, myredBrush);
Rectangle( hDC, LOWORD(lParam), HIWORD(wParam),31,31 );
//+
// draw an empty rectangle ten pixels square
// The FrameRect() function draws a border around the
//specified rectangle by using the specified brush rather
//than the current pen.
//
// The width and height of the border are 
//always one logical unit.
//-
myRectangle.top = 0;
myRectangle.left = 0;
myRectangle.bottom = 10;
myRectangle.right = 10;
HBRUSH myGreenBrush = CreateSolidBrush(RGB(255, 0, 0));
FrameRect( hdc, &myRectangle, myGreenBrush );
}

Windows Character Data Types

This section describes various routines and functions related to fonts and character sets used in X Windows applications and their alternatives in the Windows environment. You can use the information provided in this section to identify the front-specific and text-specific routines in your UNIX applications and implement the replacements in the Windows environment using the Win32/Win64 API.

Most of the pointer-type names are prefixed with a P or LP. For more information about character sets used by fonts, see the operating system Help documentation, or search the MSDN Web site. A best practice with characters is to declare all characters and strings as TCHAR and use the TEXT macro to declare static strings. For example:

TCHAR myString[255];
wsprintf( myString,
TEXT("This is a good example %d is a %s \n" ),
1950,
TEXT("Year")
);

For more information about wsprintf and the rest of the string functions, see the operating system Help documentation or search the MSDN Web site.

Text and Fonts

Text can be formatted by creating and using fonts and making intelligent decisions about mapping modes and kerning.

Displaying Text

This section discusses the use of fonts to display text.

Using Fonts

Fonts control the display characteristics of text. An X Windows client application can use the XLoadQueryFont and XSetFont functions to apply a font to a given graphics context, as shown in the following code.

X Windows example: Applying a font to given graphics context

#define FONT1 "-*-lucida-medium-r-*-*-12-*-*-*-*-*-*-*"
Font font1;
XFontStruct *font1Info;
main() {
Display *pDisplay;
int iScreen;
GC gc;
pDisplay = XOpenDisplay("myDisplay");
iScreen = DefaultScreen(pDisplay);
//+
// get the Graphics Context
//-
gc = DefaultGC(pDisplay,iScreen);
//+
// attempt to load the font
//-
font1Info = XLoadQueryFont( pDisplay,FONT1 );
font1 = font1Info->fid;
//+
// Set the font in the GC
//-
XSetFont( pDisplay, gc, font1 );
...
...

A Windows API-based application follows the same logic. That is, it creates or selects a font, retrieves a device context, and then selects the font object for that device context. This is shown in the following example.

Windows example: Applying a font to given graphics context

#define FONT1 TEXT(“Lucida Console”);
HFONT hFont1;
void fontDemo( HWND hWnd )
{
HDC hDC;
HFONT hOldFont;
//+
// get the Device Context
//-
hDC = GetDC( hWnd );
//+
// attempt to load the system font
//-
hFont1 = (HFONT)GetStockObject (SYSTEM_FONT);
//+
// Set the font in the GC
//-
hOldFont = (HFONT)SelectObject( hDC, hFont1 );
...
Creating Fonts

The short example in this section uses the font specified by SYSTEM_FONT, which duplicates the default, although developers are likely to use something more creative. The Windows API CreateFont, CreateFontIndirect, CreateScalableFontResource, and CreateFontIndirectEx functions provide the capability to create logical fonts based on the fonts loaded on the system.

Windows example: Creation of fonts

#define MY_FONT_FACE TEXT("Lucida Console")
//+
// fontAttribute Option Bits
//-
#define fontAttribute_BOLD 0x01
#define fontAttribute_CROSSED_OUT 0x02
#define fontAttribute_UNDERLINED 0x04
#define fontAttribute_ITALIC 0x08
typedef struct {
unsigned char fontSize;
unsigned char fontStyle;
TCHAR *fontFace;
} tyFONT_ATTRIBUTE;
HFONT createFont( tyFONT_ATTRIBUTE *fontAttributeObject )
{
HFONT hFont;
LOGFONT lf;
//+
// these are completely arbitrary values for this example code.
// they simply associate a width and height with a
// font size number found in the tyFONT_ATTRIBUTE struct.
//
// For example fontSize == 2 (used to index these two arrays)
// will produce a 12x8 font
//-
int fontHeight[] = {8,8,12,16,16,24,32, 32,48,64,64,96,128,128,192};
int fontWidth [] = {6,8, 8,12,16,16,24, 32,32,48,64,64, 96,128,128};
//+
// pick a font face
//-
lstrcpy( lf.lfFaceName, fontAttributeObject->fontFace );
//+
// protect against running out of the arrays above
// and pick a default behavior of "2"
//-
if ( fontAttributeObject->fontSize > 14 )
fontAttributeObject->fontSize = 2;
if ( fontAttributeObject->fontStyle & fontAttribute_BOLD )
lf.lfWeight = FW_MEDIUM;
else
lf.lfWeight = FW_LIGHT;
lf.lfItalic = (unsigned char)( fontAttributeObject->fontStyle &
fontAttribute_ITALIC );
lf.lfUnderline = (unsigned char)( fontAttributeObject->fontStyle &
fontAttribute_UNDERLINED );
lf.lfStrikeOut = (unsigned char)( fontAttributeObject->fontStyle &
fontAttribute_CROSSED_OUT );
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfCharSet = ANSI_CHARSET;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DRAFT_QUALITY;
lf.lfPitchAndFamily = FF_MODERN | FIXED_PITCH;
lf.lfHeight = fontHeight [ fontAttributeObject->fontSize ];
lf.lfWidth = fontWidth [ fontAttributeObject->fontSize ];
hFont = CreateFontIndirect(&lf);
return( hFont );
}
//+
// example using createFont()
//-
void fontDemo( HWND hWnd )
{
HDC hDC;
HFONT hOldFont;
HFONT hFont1;
tyFONT_ATTRIBUTE fontAttribute;
//+
// get the Device Context
//-
hDC = GetDC( hWnd );
//+
// attempt to create a font
//-
fontAttribute.fontSize = 2;
fontAttribute.fontStyle = (fontAttribute_BOLD | fontAttribute_ITALIC );
lstrcpy( fontAttribute.fontFace, MY_FONT_FACE );
hFont1 = createFont( &fontAttribute );
//+
// Set the font in the GC
//-
hOldFont = (HFONT)SelectObject( hDC, hFont1 );

Note Additional information about creating and using logical fonts in a Windows API-based application is available on the MSDN Web site at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnprogwin/html/ch17-03.asp.

Drawing Text

Because simple is often better, this discussion starts with the X Windows XDrawString function and the Windows API TextOut function. Both functions require a context to draw on the x and y coordinates, the string, and the string length in characters. The examples in this section draw the string “Hello World” in the current font and colors at the specified coordinates.

It is often desirable to set a particular font or color before writing the text. These examples show how the two systems perform these tasks.

A programmer can code font and text display in X Windows as shown in the following code:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

font = XLoadQueryFont (display, “fixed”);
XSetFont (display, gc, font->fid);
XSetBackground(display, gc, WhitePixel(display, screen));
XSetForeground(display,
gc, BlackPixel(display, screen));
XDrawString( display, d, gc, x, y, “Hello World”, 11 );

X Windows provides explicit definitions of 8-bit and 16-bit character functions with XDrawString and XDrawString16. Likewise, the Windows API provides TextOutA for ASCII (8-bit characters) and TextOutW for Wide Char (16-bit UNICODE characters).

The TextOut function is actually a macro that resolves correctly to TextOutA or TextOutW based on the status of the UNICODE definition, as follows:    

#define UNICODE
#define _UNICODE
TextOut()... // this will result in TextOutW()
#undef UNICODE
#undef _UNICODE
TextOut()... // this will result in TextOutA()

One drawback of using XDrawString and TextOut is that nothing is done about erasing the background. Continually outputting strings to the same x and y coordinates results in a jumble of unreadable text strings, one upon the other. The X Windows library provides the DrawImageString function, which calculates a rectangle containing the string and fills it with the background pixel color before drawing the text in the foreground pixel color. The Windows API supports the ExtTextOut function to provide this capability. Using the Windows API ExtTextOut function requires the bounding rectangle to be calculated and passed into the function. This requires knowledge about the current font and logical display units.

A programmer can code font and text display in the Windows API as follows:

#define rgbBlack (COLORREF)RGB( 0x00,0x00,0x00 )
#define rgbWhite (COLORREF)RGB( 0xFF,0xFF,0xFF )
font = (HFONT)GetStockObject(OEM_FIXED_FONT);
oldFont = (HFONT)SelectObject( hdc, font ); // save old font
SetTextColor (hdc, rgbBlack);
SetBkColor (hdc, rgbWhite);
TextOut( hdc, x, y, "Hello World", 11);

The preceding Windows API code example uses the COLORREF type, the RGB macro, and the GetStockObject function in the following sequence:

  1. The COLORREF value specifies an RGB color and is defined as follows:

    typedef DWORD COLORREF;
    

typedef DWORD *LPCOLORREF;

  1. The RGB macro selects the red, green, blue (RGB) color combination based on the arguments supplied and the color capabilities of the output device, as follows:

    COLORREF RGB(
    

BYTE byRed, // red component of color BYTE byGreen, // green component of color BYTE byBlue // blue component of color );

  1. The GetStockObject(int objectType) function retrieves a handle to one of the stock pens, brushes, fonts, or palettes. The return value must be cast to the expected type, as follows:

    void foo() {
    

HFONT hFont; HBRUSH hBrush; hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH); }

Following are the other APIs that are used for text output:

  • DrawText 

  • DrawTextEx 

  • PolyTextOut 

  • TabbedTextOut 

The DrawText function draws formatted text in the specified rectangle, as shown in the following example. It formats the text according to the specified method, expanding tabs, justifying characters, and breaking lines.

int DrawText(
HDC hDC, // handle to DC
LPCTSTR lpString, // text to draw
int nCount, // text length
LPRECT lpRect, // formatting dimensions
UINT uFormat // text-drawing options
);

To specify additional formatting options, use the DrawTextEx function:

int DrawTextEx(
 HDC hdc,           // handle to DC
 LPTSTR lpchText,       // text to draw
 int cchText,         // length of text to draw
 LPRECT lprc,         // rectangle coordinates
 UINT dwDTFormat,       // formatting options
 LPDRAWTEXTPARAMS lpDTParams // more formatting options
);

The PolyTextOut function draws several strings using the font and text colors currently selected in the specified device context.

BOOL PolyTextOut(
 HDC hdc,        // handle to DC
 CONST POLYTEXT *pptxt, // array of strings
 int cStrings      // number of strings in array
);

The TabbedTextOut function writes a character string at a specified location, expanding tabs to the values specified in an array of tab-stop positions. The text is written in the currently selected font, background color, and text color.

LONG TabbedTextOut(
 HDC hDC,             // handle to DC
 int X,              // x-coord of start
 int Y,              // y-coord of start
 LPCTSTR lpString,        // character string
 int nCount,           // number of characters
 int nTabPositions,        // number of tabs in array
 CONST LPINT lpnTabStopPositions, // array of tab positions
 int nTabOrigin          // start of tab expansion
);
Formatting Text

The formatting functions can be divided into the following three categories:

  • Those that retrieve or set the text-formatting attributes for a device context.

  • Those that retrieve character widths.

  • Those that retrieve string widths and heights.

Text-Formatting Attribute APIs

Text-formatting attribute APIs are a set of APIs used to set or retrieve text-formatting attributes for a device context. The text formatting attributes could be the text alignment, inter character spacing, text justification, or text and background colors.

Table 6.3 lists the APIs and their functions.

Table 6.3. APIs and Their Functions

APIs

Description

SetBkColor

Sets the current background color to the specified color value or to the nearest physical color if the device cannot represent the specified color value.

SetBkMode

Sets the background mix mode of the specified device context.

SetTextAlign

Sets the text alignment flags for a device context.

SetTextCharacterExtra

Sets the intercharacter spacing.

SetTextColor

Sets the text color for a device context.

SetTextJustification

Specifies the amount of space the system should add to the break characters in a string.

GetBkColor

Returns the current background color for the specified device context.

GetBkMode

Returns the current background mix mode for a specified device context.

GetTextAlign

Gets the text-alignment setting for a device context.

GetTextCharacterExtra

Gets the current intercharacter spacing for a device context.

GetTextColor

Gets the text color for a device context.

APIs to Retrieve Character Widths

Applications must retrieve character-width data when they perform such tasks as fitting strings of text to page or column widths.

An application can use the GetCharWidth32 and GetCharWidthFloat functions to retrieve the advance width for individual characters or symbols in a string of text. The advance width is the distance that the cursor on a screen or the print-head on a printer must advance before printing the next character in a string of text. The GetCharWidth32 function returns the advance width as an integer value. If greater precision is required, an application can use the GetCharWidthFloat function to retrieve fractional advance-width values.

An application can retrieve actual character-width data by using the GetCharABCWidths and GetCharABCWidthsFloat functions. The GetCharABCWidthsFloat function works with all fonts. The GetCharABCWidths function only works with TrueType and OpenType fonts.

APIs to Retrieve String Widths and Heights

In X Windows you can rely on XTextWidth to get the length of a character string in pixels. With the Windows API, you must work a little harder to get this number.

It is necessary to understand the mapping mode. The mapping mode defines the unit of measure used to transform page-space units into device-space units. It also defines the orientation of the x and y axes of the device.

A mapping mode is a scaling transformation that specifies the size of the units used to draw operations. The mapping mode can also perform translation. In some cases, the mapping mode alters the orientation of the x and y axes in the device space.

The default mapping mode is MM_TEXT. One logical unit equals one pixel. Positive x-axis is to the right, and positive y-axis is down. This mode maps directly to the coordinate system of the device.

The Windows API SetMapMode function sets the mapping mode of the specified device context, as shown in the following code:

int SetMapMode(
HDC hdc, // handle to device context
int fnMapMode // new mapping mode
);

To calculate the size of a string in pixels, it is necessary for the current mapping mode to be MM_TEXT. The Windows API programmer can either assume the current mapping mode as the default MM_TEXT and set it to MM_TEXT by calling SetMapMode, or make sure it is MM_TEXT by using GetMapMode to retrieve it. (For more information, search for MM_TEXT on the MSDN Web site*.*)

The Windows API GetTextExtentPoint32 function returns the width and height of a string of text in logical units, as shown in the following code. Recall that setting the mapping mode to MM_TEXT returns logical units as pixels.

BOOL GetTextExtentPoint32(
HDC hdc, // handle to DC
LPCTSTR lpString, // text string
int cbString, // characters in string
LPSIZE lpSize // string size
);

The size structure resembles the following code, and is defined in Windef.h:

typedef struct tagSIZE {
LONG cx;
LONG cy;
} SIZE, *PSIZE, *LPSIZE;

The Windows API GetTextMetrics function fills a TEXTMETRIC structure with all the information about the currently selected font of the device context, as shown in the following code. The programmer can use this information to perform any number of scaling or text size calculations.

BOOL GetTextMetrics(
HDC hdc, // handle to DC
LPTEXTMETRIC lptm // text metrics
);

The TEXTMETRIC structure contains basic information about a physical font, as shown in the following example. All sizes are specified in logical units; that is, they depend on the current mapping mode of the display context.

typedef struct tagTEXTMETRIC {
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
TCHAR tmFirstChar;
TCHAR tmLastChar;
TCHAR tmDefaultChar;
TCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC, *PTEXTMETRIC; 

The Windows API GetTextExtentExPoint gets the number of characters in a string that will fit within a space.

BOOL GetTextExtentExPoint(
 HDC hdc,     // handle to DC
 LPCTSTR lpszStr, // character string
 int cchString,  // number of characters
 int nMaxExtent, // maximum width of formatted string
 LPINT lpnFit,  // maximum number of characters
 LPINT alpDx,   // array of partial string widths
 LPSIZE lpSize  // string dimensions
);

More Windows API Text Functions

The following Windows API functions are also useful for working with text:

  • CreateSolidBrush

  • GetSysColor

  • SetTextColor

  • GrayString

This section discusses these functions and shows examples of their use.

The CreateSolidBrush function creates a logical brush that has the specified solid color, as shown in the following example:

HBRUSH CreateSolidBrush(
COLORREF crColor // brush color value
);

The GetSysColor function retrieves the current color of the specified display element, as shown in the following example. Display elements are the parts of a window.

DWORD GetSysColor( int nIndex );

The SetTextColor function sets the text color for the specified device context to the

specified color, as shown in the following example:

COLORREF SetTextColor(
HDC hdc, // handle to DC
COLORREF crColor // text color
);

The following example incorporates the use of DrawText, CreateSolidBrush,

GetSysColor ,  and SetTextColor:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

RECT myRectangle;
//+
// create a brush
//-
HBRUSH myBackgroundBrush =
CreateSolidBrush(
GetSysColor(COLOR_BACKGROUND) // color of system background
);
//+
// set the text color to the system's button text color
//-
SetTextColor(
hdc,
GetSysColor(COLOR_BTNTEXT) //color of text on buttons
);
// calculate myRectangle
//+
// fill in (erase) the area inside the rectangle with the
// system's background color
//-
FillRect( hdc, &myRectangle, myBackgroundBrush);
//+
// The DrawText function uses the device context's
// selected font, text
// color, and background color to draw the text.
// Unless the DT_NOCLIP
// format is used, DrawText clips the text so that
// it does not appear
// outside the specified rectangle.
//-
DrawText( hdc,
myString,
_tcsclen(myString), // use _tcsclen() vs. strlen()
&myRectangle,
(DT_CENTER | DT_SINGLELINE )
);

The GrayString function draws gray text at the specified location, as shown in the following example. The function draws the text by copying it into a memory bitmap, graying the bitmap, and then copying the bitmap to the screen. The function grays the text regardless of the selected brush and background. GrayString uses the font currently selected for the specified device context.

BOOL GrayString(
HDC hDC, // handle to DC
HBRUSH hBrush, // handle to the brush
GRAYSTRINGPROC lpOutputFunc, // callback function
LPARAM lpData, // application-defined data
int nCount, // number of characters
int X, // horizontal position
int Y, // vertical position
int nWidth, // width
int nHeight // height
);

Text Widgets and Controls

A text widget or control is used to display, enter, and edit text. The exact functionality of a text widget or control depends on how its resources are set.

X Windows example: Widget functionality

In X Windows, the widget functionality is set as shown in the following example:

text = XtVaCreateManagedWidget ( "myTextWidget",
asciiTextWidgetClass,
parentWidget,
XtNfromHoriz,
quit,
XtNresize,
XawtextResizeBoth,
XtNresizable,
True,
NULL);

Windows example: Widget functionality

In Windows API and GDI, the control functionality is set as shown in the following example:

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

//+
// Create an edit Control.
//-
HWND handleToThisEditControl;
handleToThisEditControl =
CreateWindow( TEXT("EDIT"), //ß the type of control
TEXT("Some Text"), //ß edit control text
(WS_CHILD |
WS_VISIBLE |
ES_READONLY |
ES_LEFT |
ES_UPPERCASE), //ß the control style
XpositionInParent,
yPositionInnParent,
CONTROL_WIDTH_IN_DEVICE_UNITS,
CONTROL_HEIGHT_IN_DEVICE_UNITS,
handleOfParentWindow, //ß parent window
(HMENU)NUMBER_USED_TO_ID_THIS_EDIT_CONTROL,
appContext,
NULL );
//+
// Turn off Read Only
//-
SendMessage( handleToThisEditControl ,
EM_SETREADOINLY,
(WPARAM)FALSE, //ß set read only false
(LPARAM)NULL );
//+
// set the edit control's text
//-
SetWindowText( handleToThisEditControl, 
TEXT("Some New Text") );
//+
// retrieve the edit control's text as text
//-
GetWindowText( handleToThisEditControl,
myStringBuffer,
myStringBufferMaxSize );
//+
// retrieve the edit control's text as an integer
//-
myIntegerValue =
GetDlgItemInt( handleOfParentWindow,
NUMBER_USED_TO_ID_THIS_EDIT_CONTROL,
&resultFlag, // did the translation succeed ?
FALSE ); // no this is an unsigned number

Property Sheets

A property sheet is a modal secondary window that allows the user to view and edit the properties of an item. You can also implement a property sheet as a modeless dialog. For example, property sheets can be used to display font and border properties for a worksheet, to set the properties of a device (such as a disk drive, printer, or mouse), or to display file system properties for a folder view.

A property sheet consists of a number of property pages. It is an instance of CPropertySheet.

After a property page is designed, while creating the class for this dialog box, ensure that the base class is CPropertyPage. It is attached to a property sheet using the CPropertySheet::AddPage function, as shown in the following code:

// CPage1, CPage2 and CPage3 are CPropertyPage derived classes
CPage1 p1;
CPage2 p2;
CPage3 p3(this);
CPropertySheet dlg;
dlg.SetTitle("Functions");
dlg.AddPage(&p1);
dlg.AddPage(&p2);
dlg.AddPage(&p3);
dlg.DoModal();

CPropertySheet::SetTitle can be used to set the title for the property sheet. And as seen in the previous code, a property sheet can be invoked using DoModal.

Toolbars

The toolbar is an object of the CToolBar class. Toolbars are control bars derived from the CControl Bar.

The toolbar is made up of a number of bitmaps, which can be painted using various tools. These bitmaps represent the toolbar buttons. Clicking them sends a command message. These buttons are associated with an ID, which can be viewed using the Properties window. The Properties window appears when you double-click the toolbar button. The prompt and ToolTip appear when the mouse passes over a button. The prompt is the message in the Status Bar.

The toolbar buttons and the menu items can be mapped to the same ID if their functionalities are the same, so that they can use the same handler.

The toolbar can be loaded using the LoadToolBar method of the CToolBar MFC class.

Update Command Handlers of Toolbar Buttons

Command handlers of toolbar buttons are similar to the Menu UpdateCommad handlers. The toolbars and status bars are displayed all the time and get updated during the idle time processing and during display of menu popups.

Update messages for toolbar buttons can be processed using the CCmdUI::Enable member function and the CCmdUI::SetCheck member function.

Status Bars

Status bars are control bars derived from the CControlBar class and can be created using the CStatusBar MFC class. Status bars are made up of a number of panes; the text for the panes is set using the SetPaneText function.

Following is the code to create a Status Bar, where m_wndStatusBar is an object of the MFC class CStatusBar.

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

static UINT indicators[] =
{
    ID_SEPARATOR,      // status line indicators 
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
};
 if (!m_wndStatusBar.Create(this) ||    
         !m_wndStatusBar.SetIndicators(indicators,
         sizeof(indicators)/sizeof(UINT)))    {
        TRACE0("Failed to create status bar\n");
        return -1;   // fail to create    }

Printing

This section discusses the APIs involved with printing in UNIX and Windows. You can use the information provided in this section to analyze various routines and APIs used in your UNIX applications and to identify the replacement implementation in the Windows environment using the Win32/Win64 API.

Printing Documents

The following topics discuss the various ways of printing documents in the UNIX and Windows environments.

Printing Using System Commands

In UNIX, system commands such as lp (in System V) and lpr (in BSD) are used to print documents. Windows provides the print system command for printing documents. Following is the syntax of print command:

PRINT [/D:device] [[drive:][path]filename[...]]

Where,

/D:device

Specifies a print device,

drive 

Specifies the drive in which the file to be printed is located,

path 

Specifies the path in which the file is located, and

filename 

Specifies the exact name of the file to be printed with its extension.

The following command when entered at the MS-DOS® prompt prints the document called MyDocument.doc through the printer named MyPrinter.

PRINT /D:MyPrinter C:\MyDocument.doc

The print command can be executed by invoking the system command within application programs written in C/C++ or any other supporting language. Using the system command in an application for the earlier mentioned DOS command would be:

System(“PRINT /D:MyPrinter C:\MyDocument.doc”);
Printing Using APIs

X Windows libraries provide extended facilities for printing options in UNIX systems.

X Windows example: Printing a document

The following is sample code in X Windows that helps in printing a document.

#include <X11/Xlib.h>
#include <X11/extensions/Print.h>
main()
{
  Display *pdpy;
  Screen *pscreen;
  Window pwin;
  XPPrinterList plist;
  XPContext pcontext;
  int plistCnt;
  char *attrPool;
  #define NPOOLTYPES 5  
  XPAttributes poolType[NPOOLTYPES] ={XPJobAttr,
  XPDocAttr,XPPageAttr,XPPrinterAttr,XPServerAttr};
  int i;
  unsigned short width, height;
  XRectangle rect;
  char *printServerName = ":1";
  char *mylaser = "varos";
  /*
   * connect to the X print server 
   */
  pdpy = XOpenDisplay( printServerName );
  /*
   * see if the printer "mylaser" is available
   */
  plist = XpGetPrinterList (pdpy, mylaser, &plistCnt );
  /*
   * Initialize a print context representing "mylaser"
   */
  pcontext = XpCreateContext( pdpy, plist[0].name );
  XpFreePrinterList( plist );
  /*
   * Possibly modify attributes in the print context
   */
  for(i=0;i < NPOOLTYPES;i++) {
  if(attrPool = XpGetAttributes( pdpy, pcontext, poolType[i] )) {
    /* twiddle attributes */
    /*
     XpSetAttributes( pdpy, pcontext, poolType[i],
              attrPool, XPAttrMerge );
    */
    XFree(attrPool);
  }
  }
  /*
   * Set a print server, then start a print job against it
   */
  XpSetContext( pdpy, pcontext );
  XpStartJob( pdpy, XPSpool );
  /*
   * Generate the first page
   */
  pscreen = XpGetScreenOfContext( pdpy, pcontext );
  XpGetPageDimensions( pdpy, pcontext, &width, &height,
       &rect);
  pwin = XCreateSimpleWindow( pdpy, RootWindowOfScreen( pscreen ),
        rect.x, rect.y, rect.width, rect.height, 2,
        BlackPixelOfScreen( pscreen),
        WhitePixelOfScreen( pscreen));
  XpStartPage( pdpy, pwin );
  /* usual rendering stuff..... */
  XpEndPage( pdpy ); 
  XpStartPage( pdpy, pwin );
  /* some more rendering.....  */
  XpEndPage( pdpy );
  /*
   * End the print job - the final results are sent by the X print
   * server to the spooler sub system.
   */
  XpEndJob( pdpy );
  XpDestroyContext( pdpy, pcontext );
  XCloseDisplay( pdpy );
}

Microsoft Windows implements device-independent display. In MFC, the CView class provides the basic functionality for user-defined view classes. The OnDraw member function of your view class can be used to perform screen display, printing, and print preview. For print preview, the target device is a simulated printer output to the display.

Following are the responsibilities of the view class:

  • Inform the framework of the number of pages in the document.

  • When asked to print a specified page, draw that portion of the document.

  • Allocate and de-allocate any fonts or other GDI resources needed for printing.

  • If necessary, send any escape codes needed to change the printer mode before printing a given page, for example, to change the printing orientation on a per-page basis.

Following are the responsibilities of the framework:

  • Display the Print dialog box.

  • Create a CDC object for the printer.

  • Call the StartDoc and EndDoc member functions of the CDC object.

  • Repeatedly call the StartPage member function of the CDC object, inform the view class which page should be printed, and call the EndPage member function of the CDC object.

  • Call overridable functions in the view at the appropriate times.

In Windows programming, printing options are available with the following:

  • Windows API

  • MFC and ATL

Printing Using the Windows API

A Windows program can access a printer by calling the PrintDlg function. The PrintDlg function displays a Print dialog box. The Print dialog box enables the user to specify the properties of a particular print job. The general syntax of a PrintDlg function is as follows:

BOOL PrintDlg(PRINTDLG lppd);

The argument lppd is a pointer to a PRINTDLG structure that contains information used to initialize the dialog box. When PrintDlg returns, this structure contains information about the selections of the user.

The following sample code displays a Print dialog box so that the user can select options for printing a document. The sample code first initializes a PRINTDLG structure and then calls the PrintDlg function to display the dialog box. It sets the PD_RETURNDC flag in the Flags member of the PRINTDLG structure. This causes PrintDlg function to return a device context handle for the selected printer in the hDC member. You can use the handle to render output on the printer.

On input, the sample code sets the hDevMode and hDevNames members to NULL. If the function returns TRUE, these members return handles to DEVMODE and DEVNAMES structures containing the inputs from the user and information about the printer. You can use this information to prepare the output to be sent to the selected printer.

Windows example: Displaying a print dialog box

PRINTDLG pd;
HWND hwnd;
// Initialize PRINTDLG
ZeroMemory(&pd, sizeof(PRINTDLG));
pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner  = hwnd;
pd.hDevMode  = NULL;   // Don't forget to free or store hDevMode
pd.hDevNames  = NULL;   // Don't forget to free or store hDevNames
pd.Flags    = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC; 
pd.nCopies   = 1;
pd.nFromPage  = 0xFFFF; 
pd.nToPage   = 0xFFFF; 
pd.nMinPage  = 1; 
pd.nMaxPage  = 0xFFFF; 
if (PrintDlg(&pd)==TRUE) 
{
  // GDI calls to render output. 
  // Delete DC when done.
  DeleteDC(pd.hDC);
}
Printing Using MFC and ATL

There are various options for invoking a Print dialog box with MFC programming. The most straightforward way is to create an object for the CPrintDialog class available in MFC and show a Print dialog box.

To use a CPrintDialog object

  1. Create the object using the CPrintDialog constructor.

  2. After the dialog box has been constructed, you can set or modify any value in the m_pd structure to initialize the values of the controls in the dialog box. The m_pd structure is of type PRINTDLG (which is same as that explained earlier).

  3. After initializing the dialog box controls, call the DoModal member function to display the dialog box and allow the user to select print options. DoModal returns whether the user selected the OK (IDOK) or Cancel (IDCANCEL) button.

The following is the constructor of CPrintDialog:

CPrintDialog(
  BOOL bPrintSetupOnly,
  DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES 
  | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION,
  CWnd* pParentWnd = NULL 
);

Where,

bPrintSetupOnly 

is set to TRUE to display the standard Windows Print Setup dialog box. And it is set to FALSE to display the Windows Print dialog box.

dwFlags 

Provides one or more flags that can be used to customize the settings of the dialog box, combined using the bitwise OR operator.

pParentWnd 

Provides a pointer to the parent or owner window of the dialog box.

The following sample displays a print dialog box and creates a printer device context from the DEVMODE and DEVNAMES structures:

// Display the Windows Print dialog box with "All" radio button 
// initially selected. All other radio buttons are disabled.
CPrintDialog dlg(FALSE);
if (dlg.DoModal() == IDOK)
{
  // Create a printer device context (DC) based on the information
  // selected from the Print dialog.
  HDC hdc = dlg.CreatePrinterDC();
  ASSERT(hdc);
}

Table 6.4. Members of the CPrintDialog Class

Member Function

Description

HDC CreatePrinterDC()

Creates a printer device context without displaying the Print dialog box.

virtual INT_PTRDoModal()

Displays the dialog box and allows the user to make a selection.

int GetCopies() const

Retrieves the number of copies requested.

BOOL GetDefaults()

Retrieves device defaults without displaying a dialog box.

CString GetDeviceName() const

Retrieves the name of the currently selected printer device.

LPDEVMODE GetDevMode() const

Retrieves the DEVMODE structure.

CString GetDriverName() const

Retrieves the name of the currently selected printer driver.

int GetFromPage() const

Retrieves the starting page of the print range.

CString GetPortName() const

Retrieves the name of the currently selected printer port.

HDC GetPrinterDC() const

Retrieves a handle to the printer device context.

int GetToPage() const

Retrieves the ending page of the print range.

BOOL PrintAll() const

Determines whether to print all pages of the document.

BOOL PrintCollate() const

Determines whether collated copies are requested.

BOOL PrintRange() const

Determines whether to print only a specified range of pages.

BOOL PrintSelection() const

Determines whether to print only the currently selected items.

The header afxdlgs.h is to be included in case the user wants to use the CPrintDialog class in the program.

A simple mapping can be done between the methods available for printing in X Windows and those available in Windows, as listed in Table 6.5.

Table 6.5. Comparing X Windows and Windows Printing Options

X Windows

Windows

Description

XOpenDisplay

CString GetDeviceName() const

Retrieves the name of the currently selected printer device.

XPCreateContext

HDC CreatePrinterDC()

Creates a printer device context.

XPStartJob

int StartDoc LPDOCINFO lpDocInfo)

int StartDoc( LPCTSTR lpszDocName)

Informs the device driver that a new print job is starting.

XPEndJob

int EndDoc()

Ends a print job started by the previous member function.

XCreateSimpleWindow

virtual INT_PTR DoModal()

Displays the Print dialog box.

XPStartPage

int StartPage()

Informs the device driver that a new page is starting.

XPEndPage

int EndPage()

Informs the device driver that a page is ending.

Plotting Documents

The following topics discuss the various ways of plotting documents in UNIX and Windows environments.

Using the Plotters in UNIX

Using the UNIX command lpr, you can send a PostScript file to a plotter by using vcplt, vcpltg, or vcpltcf with the -P option.

For example, to send the file mygraphic.ps to vcplt, the command would be:

  lpr -Pvcplt mygraphic.ps

By default, output is in color with normal or standard print quality. You can choose grayscale or specify print quality and paper size by using the -X option in the lpr command. The following are the available -X options:

  • grayscale (or greyscale)

  • pq=fast (or pq=draft)

  • pq=normal

  • pq=best

  • paper=<width>x<height> (for example, paper=20x30 means 20 inches wide by 30 inches high)

For example, to choose grayscale and “best” print quality on vcplt, the UNIX command would be:

  lpr -Pvcplt -Xgrayscale,pq=best filename.ps

Note that the paper option is rarely required because the application normally sets the paper size. If the application does not set the size, you can use the paper option to set it or accept the default paper size of 36" × 17."

Using the Plotters in Windows

The PrinterSettings class specifies information about how a document is printed, including the printer details that prints it. The following property of the PrinterSettings class returns a Boolean value, true or false, corresponding to whether the peripheral is a plotter or a raster printer:

public: __property bool get_IsPlotter();

This function can be used to identify a plotter.

Imaging

Imaging refers to how images are handled, loaded, saved, and stored in memory. This section discusses how imaging is done in UNIX and Windows.

Image Handling in UNIX

Xlib provides an image object that describes the data in memory and provides for basic operations on that data. You should reference the data through the image object instead of referencing the data directly. Supported operations include getting a pixel, storing a pixel, extracting a sub-image of an image, adding a constant to an image, and destroying the image.

typedef struct _XImage {
    int width, height;    /* size of image */
    int xoffset;    /* number of pixels offset in X direction */
    int format;        /* XYBitmap, XYPixmap, ZPixmap */
    char *data;        /* pointer to image data */
    int byte_order;        /* data byte order, LSBFirst, MSBFirst */
    int bitmap_unit;    /* quant. of scanline 8, 16, 32 */
    int bitmap_bit_order;    /* LSBFirst, MSBFirst */
    int bitmap_pad;        /* 8, 16, 32 either XY or ZPixmap */
    int depth;        /* depth of image */
    int bytes_per_line;    /* accelerator to next scanline */
    int bits_per_pixel;    /* bits per pixel (ZPixmap) */
    unsigned long red_mask;    /* bits in z arrangement */
    unsigned long green_mask;
    unsigned long blue_mask;
    XPointer obdata;/* hook for the object routines to hang on */
    struct funcs {            /* image manipulation routines */
        struct _XImage *(*create_image)();
        int (*destroy_image)();
        unsigned long (*get_pixel)();
        int (*put_pixel)();
        struct _XImage *(*sub_image)();
        int (*add_pixel)();
    } f;
} XImage;

The functions XInitImage, XPutImage, XGetImage, and XGetSubImage are available in UNIX to initialize, put, get, or copy the image.

Image Handling in Windows

The CImage class, defined in the atlimage.h file that comes with MFC 7.0, provides enhanced bitmap support, including the capability to load and save images in Joint Photographic Experts Group (JPEG), Graphics Interchange Format (GIF), Bitmap (BMP), and Portable Network Graphics (PNG) formats.

After instantiating the object of the CImage class, call Create, Load, LoadFromResource, or Attach to attach a bitmap to the object. Operator HBITMAP of the CImage class returns the Windows handle attached to the CImage object.

In addition, the operations listed in Table 6.6 are also possible with the CImage class.

Table 6.6. Member Functions of CImage Class

Member Function

Description

AlphaBlend

Displays bitmaps that have transparent or semitransparent pixels.

Attach

Attaches an HBITMAP to a CImage object. Can be used with either non-DIB section bitmaps or DIB section bitmaps.

BitBlt

Copies a bitmap from the source device context to this current device context.

Create

Creates a DIB section bitmap and attaches it to the previously constructed CImage object.

CreateEx

Creates a DIB section bitmap (with additional parameters) and attaches it to the previously constructed CImage object.

Destroy

Detaches the bitmap from the CImage object and destroys the bitmap.

Detach

Detaches the bitmap from a CImage object.

Draw

Copies a bitmap from a source rectangle into a destination rectangle. Draw stretches or compresses the bitmap to fit the dimensions of the destination rectangle, if necessary, and handles alpha blending and transparent colors.

GetBits

Retrieves a pointer to the actual pixel values of the bitmap.

GetBPP

Retrieves the bits per pixel.

GetColorTable

Retrieves red, green, blue (RGB) color values from a range of entries in the color table.

GetDC

Retrieves the device context into which the current bitmap is selected.

GetExporterFilterString

Finds the available image formats and their descriptions.

GetHeight

Retrieves the height of the current image in pixels.

GetMaxColorTableEntries

Retrieves the maximum number of entries in the color table.

GetPitch

Retrieves the pitch of the current image in bytes.

GetPixelAddress

Retrieves the address of a given pixel.

GetPixel

Retrieves the color of the pixel specified by the x and y axes.

GetTransparentColor

Retrieves the position of the transparent color in the color table.

GetWidth

Retrieves the width of the current image in pixels.

IsDibSection

Determines if the attached bitmap is a DIB section.

IsIndexed

Indicates that the colors of a bitmap are mapped to an indexed palette.

IsNull

Indicates if a source bitmap is currently loaded.

IsTransparencySupported

Indicates whether the application supports transparent bitmaps and was compiled for Windows 2000 or later.

LoadFromResource

Loads an image from the specified resource.

Load

Loads an image from the specified file.

MaskBlt

Combines the color data for the source and destination bitmaps using the specified mask and raster operation.

PlgBlt

Performs a bit-block transfer from a rectangle in a source device context into a parallelogram in a destination device context.

ReleaseDC

Releases the device context that was retrieved with CImage::GetDC.

ReleaseGDIPlus

Releases resources used by GDI+. Must be called to free resources created by a global CImage object.

Save

Saves an image as the specified type. Save cannot specify image options.

SetColorTable

Sets red, green, blue (RGB) color values in a range of entries in the color table of the DIB section.

SetPixelIndexed

Sets the pixel at the specified coordinates to the color at the specified index of the palette.

SetPixelRGB

Sets the pixel at the specified coordinates to the specified red, green, blue (RGB) value.

SetPixel

Sets the pixel at the specified coordinates to the specified color.

SetTransparentColor

Sets the index of the color to be treated as transparent. Only one color in a palette can be transparent.

StretchBlt

Copies a bitmap from a source rectangle into a destination rectangle, stretching or compressing the bitmap to fit the dimensions of the destination rectangle, if necessary.

TransparentBlt

Copies a bitmap with transparent color from the source device context to this current device context.

Additional information on using the CImage class is available at https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/vcsamSimpleImageSample.asp.

Table 6.7 lists the mapping that helps in the analogous study of the image-processing concepts in X Windows and Windows programs.

Table 6.7. Mapping Between X Windows and Windows Imaging Options

X Windows

Windows

Description

XReadBitmapFile

Attach

Reads in a file containing a bitmap into the object.

XGetImage

BitBlt

Copies a bitmap from the source device context to this current device context.

XCreateImage

Create

Creates a bitmap and attaches it to the previously constructed image object.

XDestroyImage

Destroy

Detaches the bitmap from the image object and destroys the bitmap.

XPutImage

Draw

Copies a bitmap from a source rectangle into a destination rectangle.

XFindContext

GetDC

Retrieves the device context into which the current bitmap is selected.

XGetPixel

GetPixel

Retrieves the color of the pixel specified by the x and y axes.

XDeleteContext

ReleaseDC

Releases the device context for the given resource ID.

XPutPixel

SetPixel

Sets the pixel at the specified coordinates to the specified color.

Mapping X Windows Terminology to Microsoft Windows

The graphical models of UNIX and Microsoft Windows are very different. There are conceptual similarities but little side-by-side mapping is possible. This section describes as many connections as possible. In the headings of this section, the X Windows term is followed by the corresponding Windows GDI term in the following format:

X Windows term vs. Windows term

This section enables you to map various X Windows terminologies used in your application to the corresponding Windows terminologies.

Callback vs. WindowProc

Windows uses the WindowProc function in the same capacity as Callback in X Windows. An X widget can have a list of callbacks associated with it, but in Windows, a window has a single entry point for handling messages sent to it.

Client vs. Client Window

X Windows comprises a protocol that describes how a client interacts with a server that could be running on a remote computer. How objects are drawn is the responsibility of the server. This provides device-independence for the client application because it is not responsible for knowing anything about the physical hardware. In the Microsoft Windows environment, the graphics device interface (GDI) API provides this layer of device-independence. Windows-based applications, such as X clients, are not required to access graphics hardware directly. GDI interacts with the hardware by using device drivers on behalf of the application.

A single Windows-based application can contain any number of separate windows. Each of these can have a window frame, caption bar, system menu, minimize and maximize buttons, and its own main display area, which is referred to as the client window.

In Windows, multiple document interface (MDI) applications have three kinds of windows. These are a frame window, an MDI client window, and a number of child windows. The term client window takes on a special meaning in this case. For more information about MDI, see the MDI documentation on the MSDN Web site or the Platform SDK.

Console Mode vs. Command Window

If X Windows or some other graphical user interface is not running on a UNIX system, a user must work in text only or in console mode. Microsoft Windows is exactly the opposite. If a console is not running, the user must work in GUI mode. Windows text-based mode is provided by running the Cmd.exe tool. This environment is also referred to as a command window or the MS-DOS prompt. To run the Cmd.exe tool, click Start, click Run, in the Run dialog box type cmd, and then click OK. Developers can also use the Console API to build native Windows API-based console applications. For more information, search for “Console Functions” on the MSDN Web site.

DPI vs. Screen Resolution

When starting an X Windows session, using the -dpi (dots per inch) option can improve appearance on displays with larger resolutions, such as 1600 × 1200. The -dpi option also helps to work around possible font issues. A Windows-based application is usually built with no assumptions about the capabilities of the system it will be running on. System APIs are used to calculate proper scaling and other characteristics. GetDeviceCaps is used to obtain the DPI of the system. GetSystemMetrics and SystemParametersInfo provide information about practically every graphical element needed to calculate sizes for fonts and other graphical elements. For more information, search for “dots per inch” on the MSDN Web site.

Graphics Context vs. Device Context

The X Windows graphics context contains required information about how drawing functions are to be executed. The Windows API device context provides similar information. The functions used in each are listed in Table 6.8.

Table 6.8. X Windows Graphics Context and Windows API Device Context Comparable Functions

Xlib

Windows

XtGetGC

GetDC

XtReleaseGC

ReleaseDC

XCreateGC

CreateDC

XFreeGC

DeleteDC

For more information about using graphics context and device context, see “Graphics Device Interface” earlier in this chapter.

Resources vs. Properties

In X Windows terminology, a widget is defined by its resources. Width, height, color, and font are examples of resources. Resources can be managed by using the XtVaCreateManagedWidget method or by using resource files or XtVaGetValues and XtVaSetValues functions.

In Windows terminology, a control is defined by its properties. For example, a text control has the Center Vertically, No Wrap, Transparent, Right Aligned Text, and Visible properties.

Resource Files vs. Registry

X Windows systems use configuration files referred to as resource files to store information about system settings or preferences for a particular X Windows client. In a Windows-based system, this type of information is stored in the registry. The registry stores data in a hierarchically structured tree. The Windows API has more than 40 functions to help access the registry. For more information, search for "registry" or "registry functions" on the MSDN Web site.

Resource file can take on another meaning in Windows-based application development.

Root Window vs. Desktop Window

All X Windows windows are descendents of the root window. In the Windows environment, the desktop window is a system-defined window that is the basis for all windows displayed by all applications.

/bin vs. /System32

In Windows, the /System32 directory is roughly equivalent to the /bin directory on a UNIX system. This is where the system executable files are located. The /System32 directory is located in the system root directory. To find system root, at the command prompt type set and press ENTER. This displays a listing of the current environment. In the list, locate SYSTEMROOT. Under SYSTEMROOT, there is an entry similar to SYSTEMROOT=C:\WINNT. This is the system directory, and under this directory is the /System32 directory.

/usr/bin vs. Program Files

The Program Files directory on a Windows-based system is similar to the /usr/bin directory on a UNIX system. This is a default location for user applications. In Windows, a user can create more than one such directory. Each drive, for example, has a Program Files directory. The system environment variable ProgramFiles contains the path of one default location, for example,

ProgramFiles=C:\ProgramFiles.

/usr/lib vs. LIB Environment Variable

In Windows, the path to user libraries can be to anywhere. To manage this relationship, retrieve or set the system environment variable LIB.

/usr/include vs. INCLUDE Environment Variable

In Windows, the path to user include files may be to anywhere. To manage this relationship, retrieve or set the system environment variable INCLUDE.

Pixmap (or Bitmap) vs. Bitmap

In X Windows, bitmap and pixmap have the same usage as Windows bitmaps. For example, they can be used as pictures, fill patterns, icons, and cursors. They are, however, very different in form.

X Windows example: A 16 × 16 “X” figure

The following X Windows example represents a simple 16 × 16 “X” figure.

#define simple_width 16
#define simple_height 16
static unsigned char simple_bits[] = {
0x01, 0x80, 0x02, 0x04, 0x20, 0x08, 0x10, 0x10, 0x08, 0x20, 0x04,
0x40, 0x02, 0x80, 0x01, 0x80, 0x01, 0x02, 0x20, 0x04, 0x10, 0x08,
0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80
};

Windows example: A 16 × 16 “X” figure

The following Windows example also represents a simple 16 × 16  “X” figure.

000000 42 4D 7E 00 00 00 00 00 00 00 3E 00 00 00 28 00
000010 00 00 10 00 00 00 10 00 00 00 01 00 01 00 00 00
000020 00 00 40 00 00 00 CA 0E 00 00 C4 0E 00 00 00 00
000030 00 00 00 00 00 00 00 00 00 00 FF FF FF 00 7F FE
000040 00 00 BF FD 00 00 DF FB 00 00 EF F7 00 00 F7 EF
000050 00 00 FB DF 00 00 FD BF 00 00 FE 7F 00 00 FE 7F
000060 00 00 FD BF 00 00 FB DF 00 00 F7 EF 00 00 EF F7
000070 00 00 DF FB 00 00 BF FD 00 00 7F FE 00 00

Window Manager vs. Windows Server 2003 and Windows XP

A special kind of X Windows client, called the Window Manager, provides a consistent working environment in the root window.

In a Microsoft Windows environment, the operating system itself is the window manager and it provides the desktop window. When a user logs on, the system creates three desktops within the WinSta0 windows station. For more information, search for “WinSta0” on the MSDN Web site.

Widgets are usually represented as controls in Windows API-based applications. Like the X Windows environment, the Windows API offers many widgets to choose from, and a great number of third-party versions are also available. Sometimes deciding exactly what to call which is difficult. For example, X Windows dialog boxes are widgets. In the Windows API, however, dialog boxes are not considered to be controls, although objects such as dialog boxes, buttons, and scroll bars are all windows.

X Library [Xlib] [X11] vs. Gdi32.lib

The X Windows library [Xlib][X11] is the lowest level library. Like Gdi32.lib, it provides all the basic drawing functions.

X Toolkit [Intrinsics] [Xt] vs. User32.lib

The X Toolkit (Xt) is a library that accesses the lower-level graphics functionality of Xlib (X Windows) and provides such user interface elements as menus, buttons, and scroll bars. It is similar to User32.lib except that in the Windows environment, the look and feel of widgets or controls is provided in User32.lib instead of by higher-level libraries.

Porting OpenGL Applications

OpenGL was originally developed by Silicon Graphics as a platform-independent set of graphics APIs. This has made OpenGL an attractive option for developers who want to target multiple platforms. Very little, if any, platform-specific code is required to move a graphics application from one platform to another. OpenGL extensions enable the segregation and handling of platform-specific code.

OpenGL is not, however, a set of windowing libraries. An OpenGL application with Windows uses either the windowing system of the target platform (X Windows or Windows), or a cross-platform library such as the OpenGL Graphics Library Utility Kit (GLUT). Because of licensing concerns, however, most commercial applications incorporate the target platform windowing system. Therefore, when moving a UNIX application that uses OpenGL to Windows, migration considerations similar to those for a non-OpenGL application are likely to apply. This section covers additional GUI considerations for the migration of OpenGL applications.

In addition to the windowing system itself, OpenGL applications require a context to the host windowing system. A special set of OpenGL extensions for window context have been developed. UNIX applications typically use the GLX OpenGL extensions for X Windows. Microsoft Windows-based applications typically use the WGL (wiggle) OpenGL extensions. In either case, three main functions are required:

  • Create context

    • X Windows: glXCreateContext

    • Windows: wglCreateContext

  • Make context current

    • X Windows: glXMakeCurrent

    • Windows: wglMakeCurrent

  • Delete context

    • X Windows: glXDeleteContext

    • Windows: wglDeleteContext

OpenGL contains no equivalents for the IRIS GL text-handling calls and Font Manager calls. To obtain facilities for handling full text and font, GLX OpenGL extensions for X Windows API glXUseXFont is used. This API generates a series of display lists, one for each character in the font.

The equivalent API in WGL OpenGL extension are wglUseFontBitmaps/
wglUseFontOutlines.

The wglUseFontBitmaps API creates a set of bitmap display lists for use in the current OpenGL rendering context. The set of bitmap display lists is based on the glyphs in the currently selected font in the device context. Use the bitmaps to draw characters in an OpenGL image.

The wglUseFontOutlines API creates a set of display lists, one for each glyph of the currently selected outline font of a device context, for use with the current rendering context. The display lists are used to draw 3-D characters of TrueType fonts. Each display list describes a glyph outline in floating-point coordinates.

The standard GDI font and text drawing functions draw text in a single-buffered OpenGL window. These functions cannot be used to draw text in a double-buffered OpenGL window. To draw text in a double-buffered OpenGL window, an OpenGL display list for bitmap images of characters must be built and then be executed.

To draw text in a double-buffered OpenGl window

  1. Select a font for a device context, setting the properties of the font as required.

  2. Create a set of bitmap display lists based on the glyphs in the font used by the device content, one display list for each glyph that the application will draw.

  3. Draw each glyph in a string, using those bitmap display lists.

The wglUseFontBitmaps and the wglUseFontOutlines API is used for creating the display lists.

For more information about fonts in OpenGL, refer to the operating system Help documentation or search the MSDN Web site.

After the migration, if the application still needs support for UNIX, use the C/C++ precompiler directives (#ifdef) to target the appropriate platform.

The OpenGL API is a C library on both UNIX and Windows. Fortran applications can also use OpenGL. To make it easier for Fortran applications to use OpenGL, a Fortran 90 Module often exists to handle the translation between Fortran and C-calling conventions. Most Fortran compilers on Windows provide an optional Fortran module for OpenGL.

For more information about OpenGL and platform-specific examples, refer to the following Web sites:

Download

Get the UNIX Custom Application Migration Guide

Update Notifications

Sign up to learn about updates and new releases

Feedback

Send us your comments or suggestions