Windows Foundation Classes Programming Concepts

 

Microsoft Corporation

July 13, 1998

Introduction

Windows Foundation Classes for Java (WFC) provides a framework of Java packages that support components targeted for the Microsoft® Windows® operating system and the Dynamic HTML object model. WFC is tightly integrated with the Microsoft Visual J++™ development environment and provides a full set of Windows controls written in Java. Building a Java application for Windows is made much easier by this tight integration and the support of features such as IntelliSense, the Forms Designer, the Application Wizard, and the Object Browser. While these Visual J++ features put you well on your way to creating applications, you'll probably want to understand the structure and logic behind the packages and classes that make up WFC.

The purpose of this section is to provide a conceptual framework for the WFC packages and classes and to explain some of the fundamental WFC models. Many of the packages exist as infrastructure for the component model and can be ignored by developers focusing on using the WFC controls. Other packages are most easily accessed from the Visual J++ Forms Designer. When you start exploring the WFC library, you'll want to know which packages and classes are important for your particular application.

The following topics are covered in this section:

  • WFC Packages provides a high-level overview of the main packages that make up WFC.
  • Working with WFC Visual Components describes the controls, forms, and graphical objects in WFC, which include the following subtopics:
    • Windows Visual Components
    • Dynamic HTML Visual Components
  • Handling Events in WFC describes the use of delegates for handling events.
  • Localizing Your Application describes the Visual J++ and WFC support and methodology for localizing your project in various languages.
  • Using WFC Application Services describes some of the core application features and includes the following subtopics:
    • Starting and Quitting an Application
    • Handling Application Events
    • Accessing System Information
    • Performing Clipboard and Drag-and-Drop Operations
  • Using Java Threads with WFC describes the threading model for WFC and includes the following subtopics:
    • Mixing Java and Win32 Threading Models
    • Creating and Exiting a Thread
    • Using Thread Storage
    • Working with Thread Exceptions

WFC Packages

The basic foundation blocks of WFC are Windows and Dynamic HTML. WFC is rooted firmly in the Win32 Windows programming model, enabling you to use Java to write Windows-based applications that take advantage of Windows user-interface controls, events, and system services. WFC is also rooted in the Dynamic HTML object model, which enables you to create both client and server HTML pages that use the power of Dynamic HTML directly from Java.

At the heart of these technologies are native dynamic-link libraries (DLLs) that provide the core API of the WFC infrastructure. These libraries are made available to the Java language thanks to two different technologies: the JActiveX tool and J/Direct™. If the DLL represents a COM/ActiveX® component, JActiveX creates wrapper classes that map the COM objects to Java objects. If the DLL is not COM-based, J/Direct is used to call directly into the DLL and to marshal the data types between Java and the native language of the DLL (such as C or C++). Both these technologies take advantage of the built-in support and synergy of the JVC compiler and the Microsoft Virtual Machine for Java.

This is mostly important to know because several WFC packages are composed entirely of either COM wrapper classes (produced by JActiveX) or J/Direct classes. These classes have methods that map directly to the underlying API; they are not documented in the WFC Reference because they are not typically called directly. However, they are discussed as support classes for other packages.

Not including the native API support packages, there are seven main packages in WFC.

Package Description
com.ms.wfc.app Base classes that encapsulate Windows application operations. The Visual J++ form component template uses the services of this class. In addition to the basic Windows message handling structure, there is support for Windows features such as the Clipboard, the registry, threads, window handles, system information, and so on.
com.ms.wfc.core Base classes for the component model. This package includes support for containers, events, exceptions, properties, and the infrastructure for interoperating with features in Visual J++ such as the Forms Designer.
com.ms.wfc.data ActiveX Data Objects (ADO) Java classes that enable data access and data binding. This package also includes com.ms.wfc.data.u, the package that provides the base classes for the data-bound controls in WFC.
com.ms.wfc.html Classes used to implement Dynamic HTML in Java. These classes provide both client- and server-side support.
com.ms.wfc.io Classes used to access data streams, implementing a complete package for reading and writing serial streams, for file access, and for mapping between differing types of data streams.
com.ms.wfc.ui Core classes for the controls that ship with WFC. These classes also provide access to the Windows Graphics API.

The following are the core native API support classes in WFC.

Package Description
com.ms.wfc.ax Provides Java wrapper classes for the ActiveX interfaces.
com.ms.wfc.html.om Provides Java wrapper classes for the Dynamic HTML object model.
com.ms.wfc.ole32 Provides Java wrapper classes for OLE services.
com.ms.wfc.win32 Provides Java wrapper classes for Win32 API.

Working with the Visual Components of WFC

While there are some differences in the WFC visual components of Win32 and Dynamic HTML (DHTML) applications, there are many more similarities. These similarities enable the WFC component model to easily serve both types of applications. For example, both the Win32 and DHTML models include basic control types, such as edit boxes, check boxes, buttons, radio buttons, and combo boxes. For the most commonly used controls in Win32, there is usually a DHTML control with the same name prefaced by the letters "Dh" (for example, the com.ms.wfc.ui.Edit class has a corresponding com.ms.wfc.html.DhEdit class). Fonts, color constants, and most event types are also shared between the Win32 and DHTML models.

Of course, there are also components that are specific to each model, such as tables for DHTML or list view controls for Win32 components.

Probably the most notable difference between the WFC Win32 and DHTML components is that the DHTML components are not available from the Forms Designer. This means you must create, add, and modify DHTML elements in the code editor; however, the underlying Java code looks very similar in both models.

Windows Visual Components

The WFC framework is rooted in its visual components: WFC is integrated with Visual J++, a visual development tool, and sits on top of the Win32 API for the Windows operating system. The main package in WFC that supports the visible components is com.ms.wfc.ui and the base class for most visual elements in WFC is com.ms.wfc.ui.Control. Most of the WFC controls extend this class, including the Form class, which is the visual container for controls.

The Control Class

The Control class contains all the essential base properties, methods, and logic for manipulating a Win32 window. These methods can be categorized as follows:

  • Methods for setting and retrieving the control's properties, such as the size of the display and client rectangles, the foreground color, background color, associated brush, cursor, text, font, position, and so on. These methods have names that start with set or get (for example, setBrush and getBrush).
  • Event methods. For every event that a control generates, there are three methods implemented in the control. For example, for the move event, there is an onMove method, which triggers the event, an addOnMove method, which assigns an event handler to the move event, and a removeOnMove method, which removes the event handler. The Control object handles most basic control events.
  • Methods dealing with parent/child relationships of controls. For example, the add method adds a child control, and assignParent and getParent assign and retrieve the parent control. There are also methods for handling arrays of child controls.
  • Methods affecting the layout, z-order, painting, and input focus of the control, such as bringToFront, sendToBack, updateZOrder, performLayout, focus, show, hide, update, invalidate, createGraphics, and createWindowGraphics.
  • Low level event-processing methods. At the Win32 level, windows receive messages from the system. In the Control class, every input message to a control has a protected process method (for example, processCmdKey, processCmdKeyEvent, or processDialogKey). These methods are important only if a control extending this base class wants to override them to do special processing.
  • Methods relating to window handles, messages, and thread invocation. These are available for programmers experienced with the Win32 programming model. For example, createHandle, destroyHandle, getRecreatingHandle, fromHandle, and fromChildHandle all deal with window handles, and sendMessage and reflectMessage allow the control access to the underlying window messages. For descriptions of the thread invocation methods, see Using Java Threads with WFC.

The Control class extends com.ms.wfc.core.Component class, which is the base class for all WFC components.

Using Forms

A form is the main visual element of an application or a custom dialog box associated with an application. The com.ms.wfc.ui.Form class serves as the foundation for forms in WFC.

The Visual J++ Forms Designer starts with the Visual J++ form template, which provides a class extending com.ms.wfc.ui.Form, and helps you to set properties on the form and add controls to it. The Form-derived class adds a method called main, not found in Form. The form is run when the com.ms.wfc.app.Application.run method is called from main and passed a new instance of the Form-based class (this code already exists in the template). For more information, see the section on "Starting and Quitting an Application." A Form-based class used as a modal dialog box can be run by calling the Form.showDialog method (showDialog also runs modal dialog boxes that are based on the com.ms.wfc.ui.CommonDialog! box class). A Form-based modeless custom dialog box can be opened by calling the form's show method, which makes the form visible.

The Form class extends com.ms.wfc.ui.Control, so it has all the Control methods plus many of its own for handling its role as a container for controls and as a window. These include methods used to:

  • Add and remove handlers for the active, closed, closing, deactivate, inputLangChange, inputLangChangeRequest, MDIChildActivate, menuComplete, menuStart, and ownedForm events.
  • Set the form's window properties, for example, to set the form's initial maximized or visible state, start position and border style; or to determine whether the form has an automatic scroll bar, a control box, or a minimize box, and whether the form's icon is in the task bar.
  • Determine the relationship of menus, controls, or other forms placed on the form, such as setting the main menu, arranging controls, supporting multiple document interface (MDI) forms, or determining whether the form receives all the control's key events.
  • Set properties when the form is used as a modal dialog box and to run and retrieve results from a dialog box when the form is an application. This includes methods to set the Accept, Cancel, and Help buttons on a dialog box, to start a dialog box, and to set and retrieve the dialog result values returned by a modal dialog box.

This list is not comprehensive but provides a general idea of what a form is. One other class in the com.ms.wfc.ui package extends Form, and that is the UserControl class. UserControl is a class for creating your own composite Form-based controls that you can install in the Toolbox.

Overview of WFC Controls

All visible WFC controls reside in the com.ms.wfc.ui package. With over 240 classes in this package, it can be difficult to immediately determine which classes you want to use. Fortunately, the classes fall into several major categories, as follows:

  • Classes that are controls in the Visual J++ Toolbox and directly extend the com.ms.wfc.ui.Control class or ultimately derive from the Control class.
  • Classes that are controls in the Visual J++ Toolbox and use CommonDialog as a base class (this includes the CommonDialog class itself). CommonDialog wraps the Win32 CommonDialog API.
  • Classes that contain constant values used by controls. These classes all extend com.ms.wfc.core.Enum.
  • Classes that represent events and extend com.ms.wfc.core.Event or are event handler classes (delegates).
  • Classes that represent intrinsic Windows graphical objects such as brushes, bitmaps, colors, cursors, fonts, pens, palettes, icons, regions, and images. For pointers to detailed information on using these objects, see the next section, "Accessing Graphical Services."
  • Classes that, like Control, extend com.ms.wfc.core.Component but do not require the visual run time overhead of Control. Some examples are ColumnHeader, Menu (and MainMenu, ContextMenu, and MenuItem, which extend it), RebarBand, StatusBarPanel, ToolTip, and ImageList (and ImageListStreamer, which extends it).
  • Miscellaneous classes that wrap other Windows interfaces; these include Help, which wraps the Windows Help engine, HTMLControl, which wraps a browser, and MessageBox, which wraps the Windows message box, among others.

The following com.ms.wfc.ui classes directly extend Control. Controls that extend these classes are listed in the description.

Class Description
Animation Encapsulates a Windows animation control, a rectangular control that plays an Audio-Video Interleaved (AVI) animation file.
AxHost Wraps an ActiveX control and exposes the control as a WFC control.
Button Encapsulates a Windows button control.
Checkbox Encapsulates a Windows check box control, which is a labeled box that is checked or unchecked to select or clear an option.
ComboBox Encapsulates the Windows combo box control.
DateTimePicker Encapsulates a Windows date and time picker control, which allows users to specify date and time information.
Edit Encapsulates a Windows edit control, which is a rectangular control that the user can enter text into.
Form Represents the basic top-level window.
GroupBox Encapsulates a group box control, which is a rectangle that contains other controls.
Label Encapsulates the Windows label control, which displays a string of text that the user cannot edit.
ListBox Encapsulates the Windows list box control, which displays a list from which the user can select one or more items. ListItem is used with this class. The CheckedListBox control extends this class.
ListView Encapsulates the Windows list view control, which displays a collection of items, each consisting of an icon (from an image list) and a label.
MDIClient Represents a window that contains MDI child windows.
MonthCalendar Encapsulates a Windows month calendar control, which provides a simple calendar interface from which the user can select a date.
Panel Represents a container you can use to parent other controls visually. The TabPage class extends Panel.
PictureBox Encapsulates a Windows PictureBox control used to contain bitmaps.
ProgressBar Encapsulates the Windows ProgressBar control, which dynamically tracks the progress of an operation by moving a bar.
RadioButton Encapsulates a Windows radio button (or option button) control, which displays an option that can be selected or cleared.
Rebar Encapsulates a rebar control, which contains other controls within moveable, resizable bands. RebarBand is used with this class.
RichEdit Encapsulates a Windows RichEdit control.
ScrollBar Represents the base class for scroll bar controls. HScrollBar and VScrollBar extend ScrollBar.
Splitter Encapsulates the splitter control, which allows the user to resize docked controls at run time.
StatusBar Encapsulates the Windows status bar control. StatusBarPanel is used with this class.
TabBase Defines the base class that contains common functionality for Tab classes controls. TabControl (which uses TabPage) and TabStrip (which uses TabItem) extend this class.
ToolBar Encapsulates the ToolBar custom control. ToolbarButton is used with this class.
TrackBar Encapsulates a Windows trackbar control (also known as a slider control), which contains a slider for selecting a value in a range.
TreeView Encapsulates a Windows tree view control. TreeNode is used with this class.
UpDown Encapsulates the up-down control (sometimes called a spinner control).

Accessing Graphical Services

In the WFC environment, applications perform graphical operations by using the Graphics object, which encapsulates the native drawing capabilities of the Windows operating system. This object provides flexible support for the most commonly used drawing operations, including displaying images and icons and drawing lines, polygons, and text.

The Graphics object performs its work by wrapping a Windows device context, a system data structure that defines system graphical objects, their associated attributes, and the graphic modes affecting output to a device. Because you can retrieve the device context that underlies a Graphics object, you can use the Graphics object seamlessly with native Win32 drawing routines.

All WFC objects that extend the Control object support creating a Graphics object through the createGraphics method. In addition, all objects that extend the Image object, such as Bitmap, Icon, and Metafile, support the creation and retrieval of their associated Graphics object through the getGraphics method.

For more information on how to use this object, see "Introduction to Graphics Programming using WFC."

Dynamic HTML Visual Components

Dynamic HTML elements make up the second set of visual components in WFC. The controls in com.ms.wfc.html are based on the Dynamic HTML object model. The classes in com.ms.wfc.html are used to create new elements and also to bind to existing elements on an HTML page. These components can be created and manipulated on a client browser or on a server, which sends them to a client browser. This object model exists on several platforms. Therefore, it is not fundamentally rooted in Win32, although user interface controls tend to be similar because the standard set of buttons, list boxes, radio buttons, and so on, are present on both.

Both sets of WFC controls (Win32 and Dynamic HTML) have a similar base because they both ultimately derive from com.ms.wfc.core.Component. Components are elements that can be hosted in a container and support the IComponent interface, which has methods for siting the component. How components and containers are hooked up is of little concern to most programmers using WFC; however, because elements from both com.ms.wfc.html and com.ms.wfc.ui are based on components, they exhibit similar characteristics. For example, all components are added to their parent containers using the add method.

For a better understanding of how to use the com.ms.wfc.html package, see Programming Dynamic HTML in Java.

Handling Events in WFC

The Control base class and classes that extend it, such as buttons and edit boxes, expose standard Windows events such as click, keyPress, mouseMove, dragDrop, and others. You can work with an event in your application using delegates. You do not have to understand delegates in great detail to write event handlers in an application. However, understanding how to create and use delegates is useful if you are building controls, working with other applications that trigger events, or are using threads with WFC components. It is also interesting if you want to understand the details of the Java code created by the Forms Designer. This section provides some background on delegates and then addresses the practical aspects of handling events.

What is a delegate? A delegate declaration defines a class that extends com.ms.lang.Delegate. The JVC compiler also recognizes delegate as a keyword, providing a shortcut for creating a delegate-based class. A delegate instance can call a method on an object and pass data to that method. Most importantly, the delegate is isolated from the object it refers to and needs to know nothing about it. Therefore, it is ideal for "anonymous invocation." In other languages, this functionality is implemented as a function pointer. However, unlike function pointers, delegates are object-oriented, type-safe, and secure.

In WFC, delegates are most often used to bind events to handler methods, such as a click event on a button control to a handler method in your class. When the event occurs, the control invokes the delegate, passing it any event information. The delegate, in turn, calls the registered handler method and passes the event data. You can also use delegates to bind one event to more than one method (called multicasting); when the event occurs, each delegate in the list is called in the order in which they were added. Conversely, delegates from different events can be assigned the same handler method (for example, a toolbar button and a menu item can both call the same handler).

To work with events in your application, you use a delegate to register for notification when that event occurs for a specific control. To register, call the addOn<event> method of a control, where <event> is the name of the event you want to handle. For example, to register for the click event of a button, you call the button object's addOnClick method.

The addOn<event> method takes as a parameter an instance of a delegate, typically an existing WFC delegate that is associated with specific event data. In the addOn<event> call, the delegate instance is created with a reference to the method you want to bind the event to. The following example shows how you would bind the event handler "btnOK_Click" (in the current class) to the click event of a button called btnOK.

Button btnOK = new Button();
btnOk.addOnMouseClick( new EventHandler( this.btnOK_Click ));

For most events, you can create and pass an instance of the generic EventHandler delegate, which passes a generic Event object. However, some events use special event handler classes when they include extra, event-specific information. For example, mouse movement events typically include information such as the mouse cursor location. To get this type of information, you create and pass an instance of the MouseEventHandler class, which passes a MouseEvent object to the handler. Keyboard events require the KeyEventHandler to get information about the status of SHIFT keys, and so on (this handler passes a KeyEvent object).

All WFC event handler delegate classes extend com.ms.lang.Delegate. Most of them are in the com.ms.wfc.ui package with names that end in EventHandler. All WFC events extend com.ms.wfc.core.Event, have names that end in Event, and can be found in the com.ms.wfc.ui package.

**Tip   **In the Forms Designer, you can use Events view in the Properties window to bind an event to a specific method. The Forms Designer then creates the appropriate addOn<event> method and the skeleton handler for you.

When the delegate calls your handler, it passes two parameters. The first parameter is a reference to the object that originated the event. The second is an event object that can contain information about the event. A handler for the delegate from the preceding example might look like this:

private void btnOK_Click(Object source, Event e) {
if (source instanceof Button) {
String buttonName = ((Button)source).getText();
MessageBox.show("You clicked button " + buttonName);
}
}

If you used the generic EventHandler class to bind to your method, the Event object in your handler will not contain any interesting information. But if extra information is available for the event, you can extract it from the specific event object. The following is what the delegate and handler might look like for a mouse movement event. The MouseEvent object exposes properties that allow you to get the mouse position.

// This is the request for notification.
Button btnTest = new Button();
// Note that the addOn<event> method uses the MouseEventHandler class.
btnTest.addOnMouseMove( new MouseEventHandler(this.btnTestMouseMove));
// This is the handler for the mouse movement event.
private void btnTestMouseMove(Object source, MouseEvent e){
edit1.setText( e.x + ", " + e.y);
}

If you want to handle events for multiple controls or multiple events for the same control, you request a separate notification for each control/event combination. Multiple notifications can specify the same handler; for example, all the buttons on a toolbar might call the same handler for their click event. You can use the source object passed to the event handler to get details about which button was clicked. (Typically, you cast the object passed to the handler into the appropriate class to be able to invoke methods from the appropriate class.)

The following example shows code that defines buttons for a toolbar and requests notification for their click events, along with the method used to handle them.

private void initEventHandlers() {
Button buttonNew = new Button();
Button buttonSave = new Button();
Button buttonExit = new Button();
// All events are routed to the same handler.
buttonNew.addOnClick( new MouseEventHandler( this.toolbarClick) );
buttonSave.addOnClick( new MouseEventHandler( this.toolbarClick) );
buttonExit.addOnClick( new MouseEventHandler( this.toolbarClick) );
}
// common event handler
private void toolbarClick( Object source, Event e){
String buttonName;
if (source instanceof Button) {
buttonName = new String((Button)source).getText()); 
MessageBox.show("You clicked button " + buttonName);
}
}

Localizing Your Application

WFC and the Visual J++ Designer provide a simplified means for developing multilingual applications. A WFC application can be created in several localized language versions where the only difference between versions is a binary resource file. The naming convention for each resource file indicates the languages it supports, and the correct resources are loaded at run time according to the user's locale setting.

There are two parts to understanding localization concepts: design-time implementation and run time support. Certain properties of visual elements (forms and controls) are understood by Visual J++ to be localizable. At design time, Visual J++ is used to serialize these localizable properties to a binary resource file. For example, the text, font, and size of a control can change between language versions. At run time, when the application is loaded, the system loads the resources that correspond to the client thread after determining the user's locale.

To create a localized version of your application, design the visual layout using Visual J++, set the form's localizable property to true, and save the form. Visual J++ automatically creates a binary resource file and serializes all localizable properties to it.

When a form's localizable property is set to true, Visual J++ always saves resources to a single resource file with the name Form.resources, where Form is the name of the main form (for example, Form1.resources). Each version that you create will be saved to this resource file name. After creating each new version, you make a copy of this resource file and rename it to the appropriate language locale name using the standard Windows locale suffix (for example, Form1_jpn.resources for a Japanese version) using the Windows Explorer or MS-DOS commands.

**Important   **Be sure to save your original layout with a new name before laying out and saving any localized versions. This will be your master .resources file.

As an example scenario, assume you want to create American English, French, and Japanese versions of your application, whose main form is called Zippo.java. Also assume you start with the English version (although this is not necessary). First, lay out the form in English and set the localizable property to true. When you save the form, the file Zippo.resources is created. Now use the Windows Explorer or MS-DOS commands to make a copy of Zippo.resource and rename it as Zippo_enu.resources (enu is the local suffix for American English.)

Next, in the Visual J++ Designer, change your default language to French, and lay out the controls with properties localized in French. When you are finished, save the form again, overwriting the previous version of Zippo.resources. Again, make a copy of Zippo.resources and rename it as Zippo_fra.resources.

To test this version, in the Regional Settings dialog box in Control Panel, select the locale: French (Standard), in this case. (There is no need to restart your computer; the locale will be changed on the local thread.)

Using WFC Application Services

The com.ms.wfc.app package contains many classes that provide WFC application services. Many of these operations belong to the Application object itself. These operations have mostly to do with creating threads, starting the application, handling application events, and so on. Because understanding Java threads is important, it is discussed in its own section, "Using Java Threads with WFC."

Other operations that qualify as application services pertain to those provided by the Win32 operating system. These include accessing the Windows registry, accessing Clipboard data, and retrieving system information, among other operations.

Starting and Quitting an Application

The Application.run method starts a WFC application. This is typically placed in the main method of the Form-based class that constitutes the main application form. Application.run has overloaded methods that take either no parameters or one parameter specifying the form class that represents the main window of the application. For example, the following is a typical form of this call:

public static void main(String args[])
{
Application.run(new MyMainWindow());
}

If a form is passed to the run method, the form's visible property is automatically set to true, and an onClosed event handler is added to the form. The onClosed event handler calls the Application.exitThread method when the form is closed. If no form is passed, the application runs until Application.exit is called, shutting down all threads and windows on the application, or until exitThread is called, shutting down just the application's current thread.

Handling Application Events

You use the Application object to assign event handlers for five different events that occur in the context of the application: applicationExit, idle, settingChange, systemShutdown, and threadException. The following addOn methods can be called to define event handlers for these events.

Application Method Description
addOnApplicationExit Specifies a handler that is called when the application quits. You can clean up application resources here that will not be released by garbage collection. (To force the application not to quit, specify a handler for the form's closing event.)
addOnIdle Specifies a handler that is called when the application's message queue is idle, for example, to perform background operations or application cleanup.
addOnSettingChange Specifies a handler that is called when the user changes window settings.
addOnSystemShutdown Specifies a handler that is called immediately before a system shutdown initiated by a user. This provides an opportunity to save data.
addOnThreadException Specifies a handler that is called when an untrapped Java exception has been thrown, allowing the application to gracefully handle the exception. This event handler takes a com.ms.wfc.app.ThreadExceptionEvent object, which has one field that represents the exception thrown.

All these "addOn" methods have reciprocal "removeOn" methods to remove the event handler.

Accessing System Information

The Win32 system contains a large amount of information that is accessible to a WFC application or component. Most of this access is through classes in the com.ms.wfc.app package. Much of this information is stored in the Windows registry and accessed through the RegistryKey and Registry classes. Other system information, such as Windows display element sizes, operating system settings, network availability, and the hardware capabilities, are accessed using static methods in the com.ms.wfc.app.SystemInformation****class. System time is available using the com.ms.wfc.app.Time class.

This section provides an overview of how a WFC application can access this system information.

Windows registry information

The RegistryKey class in the com.ms.wfc.app package contains methods to access the Windows system registry. Use the methods in this class to create and delete subkeys, to get the count and names of subkeys for the current key, and to retrieve, set, and delete values assigned to subkeys.

The com.ms.wfc.app.Registry class contains fields holding RegistryKey objects that represent the root keys of the registry (those starting with HKEY_). (Root RegistryKey objects can also be instantiated using the getBaseKey method.) Methods can be called on any RegistryKey object to enumerate and manipulate keys and key values in the subkey tree below the root object. For example, the following code obtains an array of subKey names under the HKEY_CURRENT_USER key and the number of names in that array:

int subKeyCount;
String[] subKeyNames;
subKeyNames = Registry.CURRENT_USER.getSubKeyNames();
subKeyCount = Registry.CURRENT_USER.getSubKeyCount();

Similarly, any subkey can be retrieved or set given its path, and subkey value names and data can be retrieved or set given the value name. The following example shows retrieving the most recently used file names in Visual Studio and displaying them in an edit box:

String path; // Holds the path name.
String[] valueNames; // Holds array of MRU file names in the key.
int valueCount; // The number of MRU file names in valueNames.
path = new String("Software\\Microsoft\\VisualStudio\\6.0\\FileMRUList");
RegistryKey subKey = registry.CURRENT_USER.getSubKey( path );
// Get the file names and the number of file names.
valueNames = subKey.getValueNames();
valueCount = subKey.getValueCount();
if (valueCount > 0)
for (int i = 0; i < valueCount; ++i){
// Get the value, which is the actual file name.
String value = new String((String)subKey.getValue(valueNames[i]));
// Concatenate the name ("1", "2", etc.) with the file name value.
String valString = new String(valueNames[i] + " " + value);
// Add this to the edit box.
edit1.setText(edit1.getText()+ valString +"\r\n");
}

You can also create new keys, using the createSubKey method and set values in that key using the setValue method.

Locale information

Locale information provides details about the language and regional settings on the user's computer. There are many characteristics about a language or region that are stored. These include the character set, international telephone codes, how monetary information is displayed, which calendar is used, the measurement system, and so on.

This information is typically set using the Regional Settings dialog box in Control Panel, but it is also available programmatically. In WFC this access is provided through the methods in the com.ms.wfc.app.Locale class and through the many subclasses of Locale that contain field constants that pertain to Locale methods. For details about setting and retrieving this information, see the methods in the Locale class.

Time information

Another category of system information is time. The com.ms.wfc.app.Time class provides a Time object that has many capabilities, including capturing system time: The default constructor creates a Time object with the system date and time. Beyond retrieving system time information, the Time object is useful for doing many other things, such as comparing Date and Time objects, converting the time to various formats, and storing a Time object for later retrieval.

Time objects, once created, cannot be altered. However, the Time class provides many methods for creating new objects with offset time (such as addSeconds, addMinutes, addHours, addDays, and addYears). Also, there are many methods for retrieving just one of the properties of a Time object, such as the second, minute, hour, day, and so forth.

The Time object in WFC stores time as the number of hundred-nanosecond units since Jan 1, 100ad. The maximum value that can be stored in a WFC Time object is Dec 31, 10,000ad. Converting WFC Time objects to other formats (Strings, Variants, SYSTEMTIME, and so on) can cause loss of accuracy, and not all formats can store this wide of a range.

Do not confuse the Time class with another com.ms.wfc.app class called Timer. Timer is actually a control; however, it is not in the com.ms.wfc.ui package because it does not have a user interface.

Performing Clipboard and Drag-and-Drop Operations

The drag-and-drop feature in WFC is based on the Win32 (OLE) model, which implements a shortcut for copying and pasting data. When you use the Clipboard, you must perform several steps involving selecting the data, choosing Cut or Copy from the context menu, moving to the destination file, window, or application, and choosing Paste from the context menu. (The origin of the data is called the source and the destination is called the target.)

The drag-and-drop feature removes the necessity of using the context menu. Instead, it uses the action of pressing the left mouse button to capture the selected data in the source and releasing the button in the target to drop it. Drag-and-drop operations can transfer any data that can be placed on the Clipboard; consequently, the data formats for drag and drop are the same as those of the Clipboard. Data formats specify, for example, whether the data is text, bitmap, HTML, .wav, and so on. The com.ms.wfc.app.DataFormats class contains fields pertaining to each of the Clipboard formats. These field names (such as CF_TEXT) come straight from the Win32 constant names.

The data for Clipboard and drag-and-drop operations is stored in a com.ms.wfc.app class called DataObject, which implements the IDataObject interface. IDataObject defines methods for setting and retrieving the data, getting a list of data formats in the data object, and querying for the existence a specific data format.

To programmatically place data on and retrieve it from the Clipboard, use the static methods in com.ms.wfc.app.Clipboard. Clipboard.setDataObject takes an IDataObject****and places it on the Windows Clipboard; Clipboard.getDataObject returns an IDataObject from the Clipboard. The target must make sure that the data format on the Clipboard is one that it can use. To do this, it should query the data object with the IDataObject.getDataPresent method, passing it a data format that it can accept; getDataPresent returns true if this type of data is present.

Implementing a Drop Source

For any WFC control component (based on com.ms.wfc.ui.Control), the Control.doDragDrop method is called to start the operation. This is typically done in response to the user's moving the mouse with the left button pressed. Therefore, the code is placed in a mouseMove event handler where the MouseEvent object is checked to see if the left button is down, indicating the start of a drag operation. For example, the following is an event handler for a list box control containing file names:

private void listFiles_mouseMove(Object source, MouseEvent e)
{
//If the left button is down, do the drag/drop.
if(this.getMouseButtons()==MouseButton.LEFT)
{
String data = (String)listFiles.getSelectedItem();
listFiles.doDragDrop( data, DragDropEffect.ALL);
} 
}

The doDragDrop method takes the data to be transferred and a com.ms.wfc.ui.DragDropEffect object. The DragDropEffect class contains the following constants that can be combined using the bitwise OR for the intended mode of the drag-and-drop operation.

DragDropEffect Method Description
COPY Specifies that data will not be removed from the source after the transfer.
MOVE Specifies that data will be removed from the source after the transfer.
SCROLL Specifies that data will be scrolled in the target after the transfer.
ALL Specifies that data will be removed from the source after the transfer and scrolled into the target (essentially COPY | MOVE | SCROLL).
NONE Specifies that no operation is performed.

The target that receives the data in the drag-drop operation receives the dragDrop event, which contains this DragDropEffect object, so it can easily determine the intent of the operation.

Implementing a Drop Target

The drop part of the drag-and-drop operation is handled as an event. The Control class provides the event handler infrastructure for these drag-and-drop events: dragDrop; dragEnter; dragLeave; and dragOver. You can use the following methods to specify handlers for these events.

Control Method Description
addOnDragDrop Specifies a handler for data that is dropped into your control or window (when the left mouse button is released).
addOnDragEnter Specifies a handler for drop data as the cursor first enters the window.
addOnDragLeave Specifies a handler for drop data as the cursor leaves the window.
addOnDragOver Specifies a handler for drop data as the cursor is dragged across the window.

All these "addOn" methods have reciprocal "removeOn" methods to remove the event handler. As with all event handler addOn and removeOn methods in WFC, these methods take a delegate (in this case, DragEventHandler) that is created with the name of your handler method. For example, the following line adds the txtFile_dragDrop method as a dragDrop event handler:

txtFile.addOnDragDrop(new DragEventHandler(this.txtFile_dragDrop));

Of all the drag-and-drop events, the dragDrop event is the most commonly handled. Regardless of which of these events is handled, the code in the handler must do at least three things. It must first determine if it can accept the data format, and if so, it must then copy the data and optionally display it (or provide some user interface feedback that the data was dropped).

All data and information is passed in the DragEvent event. This contains, among other fields, a data field and an effect field. The DragEvent.data field contains an object that supports IDataObject that has methods to retrieve the data and the data formats and to query for the existence of a specific format.

Therefore, the handler must first call DragEvent.data.getDataPresent method with a format it will accept and then determine whether it holds that data type. If so, it can then call the DragEvent.data.getData method (passing in that data type) and retrieve the data. How the data is displayed is up to that control. The following example illustrates an edit control dragDrop event handler that displays text data dropped to it.

private void txtFile_dragDrop(Object source, DragEvent e)
{
// If text is in the object, write it into the edit control.
if (e.data.getDataPresent(DataFormats.CF_TEXT))
{
String filename=(String)e.data.getData(DataFormats.CF_TEXT);
txtFile.setText(filename);
}
}

Using Java Threads with WFC

Java is a free-threaded environment. This means that any object can call any other object, at any time, from any thread. Special care must be taken when writing objects so that their methods are atomic and thread-safe.

There are several classes that benefit from being free-threaded, and WFC has provided the locking code to make these objects thread-safe. These classes are as follows:

  • com.ms.wfc.core.Component
  • com.ms.wfc.core.Container
  • com.ms.wfc.ComponentManager
  • com.wfc.ui.Brush
  • com.wfc.ui.Font
  • com.wfc.ui.Pen

On the other hand, any object that derives from com.ms.wfc.ui.Control is apartment-threaded because of the Win32 window that is tied to each control. Additionally, most other objects in the com.ms.wfc.ui package are not synchronized, so they should also be considered to be apartment threaded. Likewise, the com.ms.wfc.io, com.ms.wfc.html, and com.ms.wfc.util packages are not thread-safe.

Mixing Java and Win32 Threading Models

WFC accesses native Win32 constructs (such as windows) from Java objects. The Win32 window manager is apartment-threaded, and Windows automatically marshals calls from one thread to another as needed. When a free-threaded object calls into an apartment-threaded object, the call must marshal to the object's apartment. This means that the free thread is blocked for a period of time while the apartment thread handles the request. Any other calls from free-threaded objects to the apartment call will block until the apartment call is free. Consequently, this can lead to deadlock situations.

So how do Java objects, which are inherently free thread, work with WFC controls? Rather than hide when thread transitions occur, WFC makes it the programmer's responsibility to request the transition. The programmer can then design an algorithm in such a way as to prevent deadlocks. This can be done by invoking a delegate on the control's thread, which in turn calls the method specified in the delegate.

To execute a given delegate on the thread that created the control's window handle and contains the message loop, use the Control.invoke or Control.invokeAsync methods from the desired control. It is important to use the control's own thread in case the control needs to re-create its window handle for any reason. The invoke method causes the thread to call the specified callback method and wait for a return. The invokeAsync method causes the thread to call the callback method without waiting for reply. All exceptions on the invoked thread are passed on to the owning control in both cases.

You can also use the Control.createGraphics object to perform background painting and animation techniques on a ui.Graphics object. Whereas the Graphics object is apartment-threaded, the createGraphics call is entirely free-threaded. This allows one thread to create a graphics object for a control in another thread.

Creating and Exiting a Thread

Free-threaded threads can be created using the standard Java method of implementing the java.lang.Runnable interface.

This sample shows a class that implements Runnable and takes two controls (a trackbar and a label) as parameters to its constructor. From the thread's run method, it transitions to the trackbar's thread by calling the trackbar's invokeAsync method. InvokeAsync passes a delegate called tDelegate (an instance of com.ms.app.MethodInvoker) that specifies a callback method called tCallBack. Inside that method, the control's thread can safely manipulate the control's properties, in this case, changing the trackbar's tick style. This causes the trackbar's window handle to be re-created. If the thread was not transitioned as demonstrated here, the trackbar would be re-created on the new thread rather than on the thread containing the message loop; in this case, the control trackbar wouldn't receive any new messages and would fail to respond.

import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
/**
* Runnable is the interface you need to implement to make a new
* java thread.
*/
public class RunnableClass implements Runnable
{
final int SLEEP = 500;
Label l; 
TrackBar tb;
/**
* This is the thread for our class.
*/
Thread thread;
/**
* Makes a special delegate so WFC can call it from the control's
* thread.
*/
MethodInvoker tDelegate = new MethodInvoker(tCallback);
/**
* Make a new Java thread; tell it to begin running via the 
* start() method.
*/
public RunnableClass (TrackBar tb, Label l)
{
this.l = l; 
this.tb = tb;
thread = new Thread(this, "RunnableClass thread");
thread.start();
}
public void run()
{
while (true)
{
/**
* Call the specified method from the label's thread.
*/
tb.invokeAsync (tCallback);
try
{
Thread.sleep (SLEEP);
}
catch (InterruptedException e)
{
}
}
}
int nCount = 0;
int nTickStyles[] = {TickStyle.BOTH,
TickStyle.BOTTOMRIGHT,
TickStyle.NONE,
TickStyle.TOPLEFT};
/**
* This code is executed on the trackbar's thread.
*/
private void tCallback()
{
int nIndex = nCount % (nTickStyles.length);
l.setText ("hello from tCallBack: " + nCount); 
tb.setTickStyle (nTickStyles [nIndex]);
nCount++;
int nValue = tb.getValue();
if (nValue >= tb.getMaximum())
tb.setValue(0);
else
tb.setValue (nValue + 1);
}
public void stopThread()
{
thread.stop(); 
}
}

Exiting a thread in this case is just a matter of running the thread's stop method. In this example, the Form class that creates the RunnableClass object calls that object's stopThread method when it is disposed. The following code fragment demonstrates this.

...
import RunnableClass;
public class SimpleRunnable extends Form
{
/**
* This is the class that implements the Runnable interface.
*/
RunnableClass runnableClass;
public SimpleRunnable()
{
// Required for Visual J++ Forms Designer support.
initForm(); 
runnableClass = new RunnableClass (tb, l); 
}
public void dispose()
{
runnableClass.stopThread();
super.dispose();
components.dispose();
}
Container components = new Container();
Edit eDescription = new Edit();
TrackBar tb = new TrackBar();
Label l = new Label();
private void initForm()
{
// Code to initialize the controls omitted ...
}
public static void main(String args[])
{
Application.run(new SimpleRunnable());
}
}

Alternately, to create a new application thread without having to implement the Java Runnable interface or extend java.lang.Thread, you can use the Application.createThread method. The createThread method takes a delegate as a parameter (MethodInvoker is often used, but any delegate can be used). In this case, all logic can be contained in one class, typically the Form-based class of the application. The following example code fragment shows how this works.

import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
public class SimpleAppThread extends Form
{
final int SLEEP = 700;
Thread thread;
// Specify the thread context to run a method on.
MethodInvoker cbDelegate = new MethodInvoker( cbThrdCallback );
public SimpleAppThread()
{
initForm();
/**
* Creates a new thread and runs the methodInvoker method
* on the new thread. The returned thread object is needed 
* so we can stop the thread when this form is closed (disposed).
* Note that thread.start() is called automatically.
*/
thread = Application.createThread (new MethodInvoker (this.methodInvoker));
}
private void methodInvoker()
{
while (true)
{
// cbThrdCallback is called on the check box's thread.
cb.invoke (cbDelegate);
try
{
Thread.sleep (SLEEP);
}
catch (InterruptedException e)
{
}
}
}
int nCount = 0;
/**
* Thread callback that sets check box alignment property.
* This code is to be executed on the check box's thread.
*/
private void cbThrdCallback()
{
cb.setText ("threadCallback loop: " + nCount++);
if (nCount % 2 == 0)
cb.setTextAlign (LeftRightAlignment.LEFT);
else
cb.setTextAlign (LeftRightAlignment.RIGHT);
}
public void dispose()
{
thread.stop();
super.dispose();
components.dispose();
}
private void cbSuspend_click(Object sender, Event e)
{
if (cbSuspend.getChecked())
{
cbSuspend.setText ("press to resume thread");
thread.suspend();
}
else
{
cbSuspend.setText ("press to suspend thread");
thread.resume();
}
}
Container components = new Container();
CheckBox cbSuspend = new CheckBox();
CheckBox cb = new CheckBox();
private void initForm()
{
// Code to initialize the controls here ...
}
public static void main(String args[])
{
Application.run(new SimpleAppThread());
}
}

Here the thread is stopped by calling the thread's stop method from the form's dispose method. The thread is not in a separate class, so its methods can be called directly from the Form-based class.

The Application class also contains the Application.exitThread method, which closes the thread's message loop and shuts down all windows on the thread (note that it does not stop or exit the thread itself). By way of contrast, Application.exit closes message loops on all threads and closes all windows.

Using Thread Storage

The WFC Application class provides support for Thread Local Storage (TLS). Each thread can allocate a slot of memory for storing data that is specific to the thread. Calling Application.allocThreadStorage returns an index to that slot. To set a value in TLS, call the Application.setThreadStorage with the index and a value you want to set. To retrieve that value, call Application.getThreadStorage. Remember to free any allocated thread storage with a call to Application.freeThreadStorage.

Working with Thread Exceptions

The com.ms.wfc.app class provides a ThreadExceptionDialog class, which is automatically displayed whenever an unhandled exception occurs in a thread. You can gain control of exceptions by using the Application.addOnThreadException method to specify your own thread exception handler. The addOnThreadException method takes a ThreadExceptionEventHandler delegate, which is constructed with your event handler method and the ThreadExceptionEvent class.

Typically, a thread exception event handler queries the exception field of the ThreadExceptionEvent object passed to it to determine the next course of action. From this thread exception handler, you can run the ThreadExceptionDialog and retrieve the dialog results in the same way as any other WFC dialog box: use the Form.showDialog method to launch the dialog box, and compare the returned results with the com.ms.wfc.ui.DialogResult class fields.