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