═══ 1. Notices ═══ First Edition (December 1994) The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you. This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this publication at any time. It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country. Requests for technical information about IBM products should be made to your IBM authorized reseller or IBM marketing representative. ═══ 1.1. Copyright Notices ═══ COPYRIGHT LICENSE: This publication contains printed sample application programs in source language, which illustrate OS/2 programming techniques. You may copy, modify, and distribute these sample programs in any form without payment to IBM, for the purposes of developing, using, marketing or distributing application programs conforming to the OS/2 application programming interface. Each copy of any portion of these sample programs or any derivative work, which is distributed to others, must include a copyright notice as follows: "(C) (your company name) (year). All rights reserved." (C) Copyright International Business Machines Corporation 1994. All rights reserved. Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp. ═══ 1.2. Disclaimers ═══ References in this publication to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of IBM's intellectual property rights or other legally protectable rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, programs, or services, except those expressly designated by IBM, are the user's responsibility. IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Licensing, IBM Corporation, 500 Columbus Avenue, Thornwood NY 10594, U.S.A. ═══ 1.3. Trademarks ═══ The following terms are trademarks of the IBM Corporation in the United States or other countries: AIX Common User Access CUA IBM Operating System/2 OS/2 PM Presentation Manager Proprinter SAA SOMobjects System Application Architecture WIN-OS/2 Workplace Shell The following terms are trademarks of other companies: C++ American Telephone and Telegraph Company CORBA Object Management Group, Inc. Helvetica Linotype Company Novell Novell, Inc. PCMCIA Personal Computer Memory Card International Association Windows Microsoft Corporation ═══ 2. Introduction ═══ This book is a programmer's guide to the Workplace Shell*, an application environment integrated with the Operating System/2* (OS/2*), with an object-oriented user interface using IBM*'s System Object Model (SOM). ═══ 2.1. The Workplace Shell: Object-Oriented User/Programming Interface ═══ The Workplace Shell constitutes the interface with which users interact with the operating system. It represents items that users most frequently manipulate as familiar objects on a Desktop. As a user interface, the Workplace Shell conforms to many of the guidelines described by the Common User Access* (CUA*). In addition to being an interface through which a user can organize and work with the operating system, the Workplace Shell provides its programming interface to you. This means that applications can blend into the operating system's user interaction model, allowing users to work with new applications in the same manner as the operating system itself. By exploiting the Workplace Shell's application programming interface, you can also reuse and build on much of the functionality already implemented by the Workplace Shell. By using the Workplace Shell methods, an application can implement its interface so that it includes familiar Workplace Shell user interaction tools such as: o Objects presented to the user on the Desktop o Common mouse/keyboard interaction techniques o Settings notebook to manipulate attributes of the application o Dynamic context menus to present operational choices to user o Object mobility via Drag and Drop operation o Application view management with the OS/2 Window list. In addition to the portion of the functions devoted to managing the presentation of the application's user interface, the Workplace Shell also provides functions (methods) to help coordinate the implementation of the application. ═══ 2.2. Objectives of This Guide ═══ This guide provides information on topics relevant to writing application programs for the Workplace Shell. These topics include: o Creating and Installing Workplace Shell Objects o Debugging Workplace Shell Applications o Object Aid: Help Methods o Object Containers: Container Methods o Object Criteria: Details Methods o Object Errors: Error Handling Methods o Object Information: Set/Query Methods o Object Initialization and Termination: Setup/Cleanup Methods o Object Memory: Memory Allocation Methods o Object Mobility: Direct Manipulation Methods o Object Persistence: Save/Restore Methods o Object Properties: Notebook Methods o Object Usage: Usage Methods o Object User Action: Pop-Up Menu Methods o REXX Utility Workplace Shell Functions o Workplace Shell and System Object Model o Workplace Shell Distributed SOM o Workplace Shell Processes and Threads o Workplace Shell Programming Interface o Workplace Shell Win Functions The contents of each of these topics is briefly described in the following sections. ═══ 2.2.1. Creating and Installing Workplace Shell Objects ═══ This chapter walks you through the Car sample which is included in the Toolkit, and through WPStyler, a complete sample program. The purpose is to provide detail information on how to create an object. For each sample, the different Workplace Shell instance and class methods used, along with the new methods introduced by each of them, are explained. Once objects are created, they can be installed on the Desktop in two ways: by running an installation program or batch file, or by using the Workplace Shell Class List Object Utility. As objects can also reside on the Launch Pad, this chapter describes the different setup strings and methods used with the Launch Pad. Finally, this chapter explains how to support printing the contents of an object from the Desktop. ═══ 2.2.2. Debugging Workplace Shell Applications ═══ Debugging a Workplace Shell application is somewhat like debugging a Presentation Manager* (PM*) application. But because Workplace Shell objects are implemented via DLLs instead of EXEs, they can be more of a challenge. This chapter describes the SOM and Workplace Shell facilities and techniques to aid debugging applications. ═══ 2.2.3. Object Aid: Help Methods ═══ While running an application or viewing a document, the user may require help on the application or document. It is important to include the help information for all applications as it is used often. This chapter describes different methods that can be overridden in order to provide help from an application window, when a user requests it. ═══ 2.2.4. Object Containers: Container Methods ═══ A container is a visual component that holds objects. CUA container control is the primary way of interacting with Workplace Shell objects. All objects with which the user interacts are simply records that have been inserted into a container control. Any Workplace Shell object can be inserted into any container control created on the Workplace process. This chapter describes the different views available for containers, and the methods used to create and manipulate containers in Workplace Shell applications. ═══ 2.2.5. Object Criteria: Details Methods ═══ The class defines the object's instance data and methods. Details data are part of instance data and define more accurately the behavior of the object. This chapter describes the general concepts of Details data and explains how to use the Details methods in Workplace Shell applications. ═══ 2.2.6. Object Errors: Error Handling Methods ═══ The Workplace Shell provides methods that you can override to design your own error handling system, using error objects. This chapter provides information on error handling methods for Workplace Shell applications. ═══ 2.2.7. Object Information: Set/Query Methods ═══ The Workplace Shell provides several set and query methods that you can use to set or to get object information, such as the default view of the object's in-use list, the object's icon, and the object's title. This chapter provides information for using object information methods. It describes how to define the behavior of Workplace Shell objects, using applicable styles. ═══ 2.2.8. Object Initialization and Termination: Setup/Cleanup Methods ═══ The Workplace Shell provides methods that you can use to setup the characteristics and behaviors of an object. Likewise, it also provides methods that you can use to cleanup after an object is no longer in use. This chapter provides information on setup and cleanup methods that are available in the Workplace Shell. ═══ 2.2.9. Object Memory: Memory Allocation Methods ═══ The Workplace Shell provides methods which you can override to design your own memory management system, or utilize to manage memory required for objects of your application. This chapter provides information on memory management methods for Workplace Shell applications. ═══ 2.2.10. Object Mobility: Direct Manipulation Methods ═══ Direct manipulation refers to the OS/2 object mobility. That is, it refers to the OS/2 user capability of moving an object from one container to another by dragging an object icon from a source container and dropping it on a target container. Direct manipulation methods allow you to specify how objects that are directly effected by such a move communicate with each other. This chapter outlines the protocols of direct manipulation with respect to their interactions with the Workplace Shell. ═══ 2.2.11. Object Persistence: Save/Restore Methods ═══ The WPObject class provides methods that support persistent objects, that is, objects for which the system saves information. These methods include save and corresponding restore methods. This chapter provides information using these state methods in Workplace Shell applications. ═══ 2.2.12. Object Properties: Notebook Methods ═══ A notebook is a visual component used to display the setttings for an object and to enable the user to change them. This chapter describes the General and Window pages of the Settings notebook, and explains how to use the notebook methods in Workplace Shell applications. ═══ 2.2.13. Object Usage: Usage Methods ═══ Every Workplace Shell object in the system has an in-use list. Object usage methods allow an object to keep track of its resources and how it is being used. This chapter provides information for using in-use lists that are associated with objects. ═══ 2.2.14. Object User Action: Pop-Up Menu Methods ═══ This chapter describes the pop-up context menus that can be used to invoke actions on Workplace Shell objects. It also provides an overview of how to create and manipulate the pop-up context menu for your Workplace Shell objects. ═══ 2.2.15. REXX Utility Workplace Shell Functions ═══ REXX combines the simplicity of a programming language such as BASIC with features that exist in more powerful languages such as C, PASCAL, or PL/1. Part of the success of REXX has been due in part to having been selected as the Systems Application Architecture* Programming Language (SAA/PL). The purpose is to provide a common look and feel across all operating systems. This is important because CUA is the standard that the Workplace Shell uses which is also part of SAA* REXX provides the facility for the Workplace Shell to create, modify, and delete objects. This chapter describes the REXX functions and how to use them in Workplace Shell applications. ═══ 2.2.16. Workplace Shell and System Object Model ═══ SOM is the object technology used for the implementation of the Workplace Shell. It provides a language neutral, object-oriented programming methodology that you can use to create Workplace Shell objects and bind them to the Workplace Shell. This chapter describes SOM's architecture, its features and environment. It describes its methods, classes, and finally provides an example of its workings. This chapter is not intended to be a SOM programming guide. It is, however, intended to serve as an introduction to SOM at a level necessary to write Workplace Shell applications. ═══ 2.2.17. Workplace Shell Distributed SOM ═══ Distributed SOM (DSOM) provides a framework that allows application programs to access objects across address spaces. That is, application programs can access objects in other processes, even on different machines. Both the location and implementation of an object are hidden from the client which accesses the object (using method calls) in the same manner regardless of its location. ═══ 2.2.18. Workplace Shell Processes and Threads ═══ The Workplace Shell's current implementation exploits the multi-threading capabilities of the OS/2 operating system. This chapter describes how the Workplace Shell is initialized, the relationship between its various threads, and ramifications on Workplace Shell method invocation. ═══ 2.2.19. Workplace Shell Programming Interface ═══ The Desktop (which also is an object), the objects that appear on the Desktop, and the underlying code supporting these objects constitute the OS/2 Workplace Shell, the default OS/2 user interface. Likewise, methods in the Workplace Shell are methods that were implemented for the creation of the Desktop object and its objects. This chapter describes Workplace Shell classes and characteristic behavior of Workplace Shell objects. ═══ 2.2.20. Workplace Shell Win Functions ═══ Applications cannot call Workplace Shell objects' methods directly. They are not clients of Workplace Shell objects, in the same sense that applications can be clients of SOM objects. Workplace Shell objects are derived from the WPObject class, which, in turn, is derived from the SOMObject class. They share all the features of SOM objects but only the Workplace Shell can directly manipulate them. Because there are times when applications might need to effect changes to the Desktop and objects on the Desktop, the Workplace Shell provides functions that permit you to proceed these changes. This chapter describes the Workplace Shell Win Functions. ═══ 3. Creating and Installing Workplace Shell Objects ═══ This chapter walks you through the CAR sample which is included in the Toolkit, and through WPStyler, a complete sample program. The purpose is to provide detail information on how to create an object. For each sample, the different Workplace Shell instance and class methods used, along with the new methods introduced by each of them, are explained. Once objects are created, they can be installed on the Desktop in two ways: by running an installation program or batch file, or by using the Workplace Shell Class List Object Utility. As objects can also reside on the Launch Pad, this chapter describes the different setup strings and methods used with the Launch Pad. Finally, this chapter explains how to support printing the contents of an object from the Desktop. ═══ 3.1. About Workplace Shell Objects ═══ This section describes the: o CAR sample and its implementation, which consists of: - Providing for persistence of the object - Changing Settings notebook pages - Removing an Item from the pop-up menu - Adding pop-up menu items - Creating and registering a new open view - Processing new pop-up menu items - Processing help for new pop-up menu items o Creation of new instances of objects o Printing objects o Launch Pad. ═══ 3.1.1. Creation of Objects ═══ The CAR sample Workplace Shell object included in the Toolkit provides an example of how to create an object. CAR is a spin-off implementation of the CAR object example used in the Systems Application Architecture: Common User Access Guide to User Interface Design. The CAR object has two views: o An Open car view, which is a representation of a CAR that moves randomly around a window. o A Settings notebook that permits the user to change the sound of the horn, on the Horn beep page, and the speed of the CAR, on the Dashboard page. The Horn beep and Dashboard pages in the CAR's Settings notebook are dialog windows whose contents are defined in a dialog template in the CAR.RC resource file. The resources are appended to the binary CAR.DLL file. The help panels associated with the dialogs are defined in the CAR.HLP help library. The association between the help panels and the dialogs is established with the dialog template in the resource file. CAR is a persistent object but not a part of the file system. Therefore, it is derived from the WPAbstract class, which is derived from the WPObject root Workplace Shell class. This means that CAR inherits the methods from WPAbstract, which, in turn, inherits all of the instance and class methods from WPObject. CAR defines new methods and overrides some instance and class methods inherited from both WPAbstract and WPObject. New methods defined for the CAR class are summarized in the following table: ┌──────────────────────┬─────────────────────────┐ │Method Name │Description │ ├──────────────────────┼─────────────────────────┤ │carQueryInfo │Gets the CAR information.│ │ │It is called by the │ │ │dialog procedure to get │ │ │the latest CAR data when │ │ │the dialog window opened.│ ├──────────────────────┼─────────────────────────┤ │carSetInfo │Sets up the CAR │ │ │information. It is called│ │ │by the dialog procedure │ │ │to update the CAR data as│ │ │the user interacts with │ │ │the dialog window. │ ├──────────────────────┼─────────────────────────┤ │wpAddDashboardPage │Inserts the Dashboard │ │ │page into the Settings │ │ │notebook. It is called by│ │ │wpAddSettingsPages. │ ├──────────────────────┼─────────────────────────┤ │wpAddHornBeepPage │Inserts the Horn beep │ │ │page into the Settings │ │ │notebook. It is called by│ │ │wpAddSettingsPages. │ └──────────────────────┴─────────────────────────┘ ═══ 3.1.1.1. Implementation of the CAR Object ═══ The implementation of the CAR object consists primarily of overrides to instance and class methods inherited from the WPObject and WPAbstract classes. The following sections describe the different instance and class methods that are overridden. ═══ 3.1.1.1.1. Providing for Persistence of the CAR Object ═══ Because the CAR class defines its own set of data, it overrides wpSaveState and wpRestoreState. These method overrides, in turn, call wpSaveLong and wpRestoreLong to save instance data defined for the CAR class. ═══ 3.1.1.1.2. Changing Settings Notebook Pages ═══ CAR creates Settings notebook pages by overriding wpAddSettingsPages inherited from WPObject. The wpAddSettingsPages method calls the new methods defined by the CAR class, wpAddDashboardPage and wpAddHornBeepPage. In turn, each of these methods calls wpInsertSettingsPage inherited from WPObject. ═══ 3.1.1.1.3. Removing an Item from the Pop-Up Menu ═══ Because the user item Print a car does not make sense for this object, the CAR class removes the Print item from the CAR object's pop-up menu by overriding wpFilterPopupMenu inherited from WPOject. ═══ 3.1.1.1.4. Adding Pop-Up Menu Items ═══ The CAR class adds the Beep horn item to its primary pop-up menu by overriding wpModifyPopupMenu inherited from WPObject. The method override for wpModifyPopupMenu calls wpInsertPopupMenuItems, also inherited from WPObject, to insert the item into the CAR's pop-up menu. The CAR class also adds the Open car item (OPEN_CAR) to its Open submenu by overriding wpModifyPopupMenu. The method override calls wpInsertPopupMenuItems to insert Open car into the Open submenu. ═══ 3.1.1.1.5. Creating and Registering a New Open View ═══ A window for the OPEN_CAR view is created and opened by calling WinCreateStdWindow. The window procedure for the client of the OPEN_CAR window registers the OPEN_CAR view and associates the OPEN_CAR view with that window by calling wpRegisterView. ═══ 3.1.1.1.6. Processing New Pop-Up Menu Items ═══ When a class defines new items for its menus, it must provide for the processing of these items when the user selects an item. This is done by overriding wpMenuItemSelected inherited from WPObject. Depending on the item the user selects, the method override for wpMenuItemSelected calls the object's wpOpen to open the OPEN_CAR view or calls carBeepHorn to beep the CAR's horn. ═══ 3.1.1.1.7. Processing Help for New Pop-Up Menu Items ═══ When a class defines new items for its pop-up menu, it also must provide for the processing of the help for these items when the user requests it. This is accomplished by overriding wpMenuItemHelpSelected inherited from WPObject. Given the item selected by the user, the method override for wpMenuItemHelpSelected calls wpDisplayHelp inherited from WPObject to display the Help dialog window for that item. The wpDisplayHelp method requires the ID for the help panel associated with the item, as well as the name of the help library where it resides. The implementation of the CAR object also demonstrates the use of: o A release order list in CAR.IDL. o External stem and prefix attributes in the class section of CAR.IDL. This allows the debugging process to be easier, because method names are externalized. o A message queue for the Workplace Shell. Object code runs on the Workplace Shell's thread. Windows associated with objects receive messages through the Workplace Shell's message queue. Objects do not need their own message queues. ═══ 3.1.2. Creation of New Instances of Objects ═══ An object template is the primary user mechanism for creating new instances of objects. Specifically, a template is a state of an object where the default Drag operation is Create another, that is, dragging and dropping the template results in the creation of an instance of the object. The visual representation of a template is the object's icon on top of a "yellow sticky pad" with the top sheet slightly peeled up, as shown in the following figure: Any object that supports the Create another item can be changed by the user to and from a template state by selecting the template checkbox on the General page in the object's Settings notebook. A template is created automatically when a class is registered, unless the class wpclsQueryStyle returns CLSSTYLE_NEVERTEMPLATE. When the operating system is first installed, template objects reside in the templates folder on the desktop. The templates folder always contains a template object for each class of object installed on the system that supports the Create another item. Any new object registered by WinRegisterObjectClass that supports the Create another item automatically appears in this folder. A template for each object class registered using this function cannot be removed from the templates folder. ═══ 3.1.3. Printing Objects ═══ To support printing the contents of an object from the Desktop-by using the object's pop-up menus or dragging the object and dropping it on the printer object-the object's class definition must override wpPrintObject inherited from its parent class. The new class is created as a subclass of an existing class. For example, if the object is to be a data file, the WPDataFile class would be used as the parent class. In the class definition file, the new class overrides wpPrintObject that it inherits from its parent class. The new class' version of wpPrintObject contains the code that prints the contents of the object. Note: It is recommended that the code in the object's version of wpPrintObject should start on a separate thread to execute the code that actually prints the contents of the object. By doing this, the control can be returned to the Workplace Shell and the user immediately. Supporting code, such as dialog windows, should be done on a separate thread as well. Your new class should allow data files that do not belong to your class to be printed as well. To do this, you should also override wpclsQueryInstanceType and wpclsQueryInstanceFilter to verify if a file is yours (that is, if its .TYPE extended attribute denotes your new class), or if it is not yours. If the file is not yours, you will want to call parent_wpPrintObject to do the printing. ═══ 3.1.4. About Launch Pads ═══ The Launch Pad is a convenient area for users. It provides them with a place to get fast access to their frequently used objects and Desktop actions. In addition to placing objects on the Launch Pad, users may place objects in drawers. A drawer is represented by the little button above an object on the Launch Pad, as shown in the following figure: The button of an open drawer contains a downward pointing arrow. The button of a closed drawer contains a upward pointing arrow. As shown in the above figure, the drawer above the OS/2 Window object is open and contains the DOS Window object. While there is no restriction on the content of the drawer, its most logical function is to hold objects that are either related or similar to the object on the Launch Pad but are less frequently used. There is no limit to the number of Launch Pads that may exist in the system. The system Launch Pad is defined as the one with an OBJECTID of . When the user double clicks the select button on a folder (or Desktop background space) the Workplace Shell looks for the system Launch Pad. For example, you can configure a different Launch Pad for a work area, so that each time that work area is opened, its Launch Pad is opened. ═══ 3.1.4.1. Launch Pad Setup Strings ═══ The Launch Pad is highly customizable. You can use the following setup strings to customize the Launch Pad: ┌──────────────┬─────────────────────┬─────────────────────────┐ │Keyname │Value │Description │ ├──────────────┼─────────────────────┼─────────────────────────┤ │DRAWEROBJECTS │A drawer number │Adds the objects to the │ │ │followed by a comma │end of the numbered │ │ │delimited set of │Launch Pad drawer: │ │ │object IDs or path │0=Launch Pad, 1=left-most│ │ │and file names. │drawer, etc. │ │ │Separate the drawer │ │ │ │number and the first │ │ │ │object with a comma. │ │ ├──────────────┼─────────────────────┼─────────────────────────┤ │FPOBJECTS │A comma-delimited set│Adds the objects to the │ │ │of object IDs or path│end of the Launch Pad. │ │ │and file names. │ │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPACTIONSTYLE │MINI │Displays the action │ │ │ │buttons as mini-icons. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NORMAL │Displays the action │ │ │ │buttons as normal or │ │ │ │large icons. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │OFF │Turns off the display of │ │ │ │action buttons. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │TEXT │Displays the actions │ │ │ │buttons as text. This is │ │ │ │the default. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPCLOSEDRAWER │YES │Closes the Launch Pad │ │ │ │drawers after opening an │ │ │ │object. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Leaves the Launch Pad │ │ │ │drawers open after │ │ │ │opening an object. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPDRAWERTEXT │YES │Displays titles of │ │ │ │objects located in │ │ │ │drawers. This has no │ │ │ │effect on objects located│ │ │ │on the Launch Pad. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Hides titles of objects │ │ │ │located in drawers. This │ │ │ │has no effect on objects │ │ │ │located on the Launch │ │ │ │Pad. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPFLOAT │YES │Keeps the Launch Pad │ │ │ │floating on top of all │ │ │ │other windows. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Does not keep the Launch │ │ │ │Pad floating on top of │ │ │ │all other windows. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPHIDECTLS │YES │Hides the frame controls │ │ │ │(title bar and system │ │ │ │menu). This is the │ │ │ │default. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Displays the frame │ │ │ │controls (title bar and │ │ │ │system menu). │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPSMALLICONS │YES │Displays objects using │ │ │ │small icons. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Display objects using │ │ │ │large icons. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPTEXT │YES │Displays titles of │ │ │ │objects located on the │ │ │ │Launch Pad. This has no │ │ │ │effect on objects located│ │ │ │in drawers. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Hides titles of objects │ │ │ │located on the Launch │ │ │ │Pad. This has no effect │ │ │ │on objects located in │ │ │ │drawers. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │LPVERTICAL │YES │Displays the Launch Pad │ │ │ │vertically. │ ├──────────────┼─────────────────────┼─────────────────────────┤ │ │NO │Displays the Launch Pad │ │ │ │horizontally. This is the│ │ │ │default. │ └──────────────┴─────────────────────┴─────────────────────────┘ These keynames can be used with the following Win and REXX functions: o WinCreateObject o WinSetObjectData o SysCreateObject o SysSetObjectData. The following example adds two objects to the first drawer of the Launch Pad: SysSetObjectData("", "DRAWEROBJECTS=1,C:\README.TXT,") The following example causes the Launch Pad to float on top: SysSetObjectData("", "LPFLOAT=YES") ═══ 3.1.4.2. Launch Pad Set Methods ═══ In addition to setup strings, methods shown in the following table provide the same functionality: ┌───────────────────────────┬─────────────────────┬────────────────────┐ │Method Name │Value │Description │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetActionButtonStyle │ACTION_BUTTONS_MINI │Displays the actions│ │ │ │buttons as │ │ │ │mini-icons. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │ACTION_BUTTONS_NORMAL│Displays the action │ │ │ │buttons as normal or│ │ │ │large icons. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │ACTION_BUTTONS_OFF │Turns off the │ │ │ │display of action │ │ │ │buttons. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │ACTION_BUTTONS_TEXT │Displays the action │ │ │ │buttons as text. │ │ │ │This is the default.│ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetCloseDrawer │TRUE │Closes the Launch │ │ │ │Pad drawer after │ │ │ │opening an object. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Leaves the Launch │ │ │ │Pad drawer open │ │ │ │after opening an │ │ │ │object. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetDisplaySmallIcons │TRUE │Displays objects │ │ │ │using small icons. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Displays objects │ │ │ │using large icons. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetDisplayText │TRUE │Displays titles of │ │ │ │objects located on │ │ │ │the Launch Pad. This│ │ │ │has no effect on │ │ │ │objects located in │ │ │ │drawers. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Hides titles of │ │ │ │objects located on │ │ │ │the Launch Pad. This│ │ │ │has no effect on │ │ │ │objects located in │ │ │ │drawers. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetDisplayTextInDrawers │TRUE │Displays titles of │ │ │ │objects located in │ │ │ │drawers. This has no│ │ │ │effect on objects │ │ │ │located on the │ │ │ │Launch Pad. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Hides titles of │ │ │ │objects located in │ │ │ │drawers. This has no│ │ │ │effect on objects │ │ │ │located on the │ │ │ │Launch Pad. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetDisplayVertical │TRUE │Displays the Launch │ │ │ │Pad vertically. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Displays the Launch │ │ │ │Pad horizontally. │ │ │ │This is the default.│ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetFloatOnTop │TRUE │Keeps the Launch Pad│ │ │ │floating on top of │ │ │ │all other windows. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Does not keep the │ │ │ │Launch Pad floating │ │ │ │on top of all other │ │ │ │windows. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetHideLaunchPadFrameCtls│TRUE │Hides the frame │ │ │ │controls (title bar │ │ │ │and system menu). │ │ │ │This is the default.│ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │FALSE │Displays the frame │ │ │ │controls (title bar │ │ │ │and system menu). │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetObjectListFromHObjects│A drawer number. │Adds the objects to │ │ │ │the numbered drawer │ │ │ │of the Launch Pad. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │The number of objects│ │ │ │to be added. │ │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │An array of HOBJECTS.│ │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │A position within the│0=Launch Pad, │ │ │drawer. │1=left-most drawer, │ │ │ │and so on. Use │ │ │ │ADD_OBJECT_FIRST to │ │ │ │add the objects at │ │ │ │the beginning of the│ │ │ │drawer. Use │ │ │ │ADD_OBJECT_LAST to │ │ │ │add the objects at │ │ │ │the end of the │ │ │ │drawer. Use a │ │ │ │position number to │ │ │ │state which objects │ │ │ │the new objects │ │ │ │should be inserted │ │ │ │after (0=first │ │ │ │object). │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetObjectListFromObjects │A drawer number. │Adds the objects to │ │ │ │the specified Launch│ │ │ │Pad drawer. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │The number of objects│ │ │ │to be added. │ │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │An array of │ │ │ │WPObject*. │ │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │A position with the │0=Launch Pad, │ │ │drawer. │1=left-most drawer, │ │ │ │and so on. Use │ │ │ │ADD_OBJECT_FIRST to │ │ │ │add the objects at │ │ │ │the beginning of the│ │ │ │drawer. Use │ │ │ │ADD_OBJECT_LAST to │ │ │ │add the objects at │ │ │ │the end of the │ │ │ │drawer. Use a │ │ │ │position number to │ │ │ │state which objects │ │ │ │the new objects │ │ │ │should be inserted │ │ │ │after (0=first │ │ │ │object). │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │wpSetObjectListFromStrings │A drawer number. │Adds the objects to │ │ │ │the specified Launch│ │ │ │Pad drawer. │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │A NULL delimited set │ │ │ │of object IDs or path│ │ │ │and file names │ │ │ │terminated by a │ │ │ │double NULL. │ │ ├───────────────────────────┼─────────────────────┼────────────────────┤ │ │A position with the │0=Launch Pad, │ │ │drawer. │1=left-most drawer, │ │ │ │and so on. Use │ │ │ │ADD_OBJECT_FIRST to │ │ │ │add the objects at │ │ │ │the beginning of the│ │ │ │drawer. Use │ │ │ │ADD_OBJECT_LAST to │ │ │ │add the objects at │ │ │ │the end of the │ │ │ │drawer. Use a │ │ │ │position number to │ │ │ │state which objects │ │ │ │the new objects │ │ │ │should be inserted │ │ │ │after (0=first │ │ │ │object). │ └───────────────────────────┴─────────────────────┴────────────────────┘ The following example adds two objects to the first drawer in the Launch Pad: PSZ pszObjectList = "C:\\README.TXT\0\0"; _wpSetObjectListFromStrings(somSelf, 1, pszObjectList, ADD_OBJECT_LAST); The following example causes the Launch Pad to float on top: _wpSetFloatOnTop(somSelf,TRUE); ═══ 3.1.4.3. Launch Pad Query Methods ═══ The following table provides the methods for querying information about the state of the Launch Pad: ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryActionButtons │Returns a pointer of array of │ │ │ACTION data structures. Each │ │ │ACTION structure has the │ │ │following elements: │ │ │ │ │ │o Pointer to the text to be │ │ │ displayed │ │ │o Handle to the icon to be │ │ │ displayed │ │ │o Menu item number that is │ │ │ passed to the Desktop via │ │ │ wpMenuItemSelected, when │ │ │ the action button is │ │ │ pressed. │ │ │ │ │ │The number of ACTION │ │ │structures in the array is │ │ │returned using parameters. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryActionButtonStyle │Returns the current setting │ │ │for the action button style: │ │ │ │ │ │o ACTION_BUTTONS_MINI │ │ │o ACTION_BUTTONS_NORMAL │ │ │o ACTION_BUTTONS_OFF │ │ │o ACTION_BUTTONS_TEXT. │ │ │ │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryCloseDrawer │Returns TRUE if the drawer is │ │ │closed after one of its │ │ │objects is opened. Otherwise, │ │ │it returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDisplaySmallIcons │Returns TRUE if objects' icons│ │ │are displayed using small or │ │ │mini-icons. Otherwise, it │ │ │returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDisplayText │Returns TRUE if titles of │ │ │objects located on the Launch │ │ │Pad are displayed. Otherwise, │ │ │it returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDisplayTextInDrawers │Returns TRUE if text is │ │ │displayed for objects that are│ │ │located in drawers. Otherwise,│ │ │it returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDisplayVertical │Returns TRUE if the Launch Pad│ │ │is displayed vertically. │ │ │Otherwise, it returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFloatOnTop │Returns TRUE if the Launch Pad│ │ │is set to float on top of all │ │ │other windows. Otherwise, it │ │ │returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryHideLaunchPadFrameCtls │Returns TRUE if the frame │ │ │controls (title bar and system│ │ │menu) are hidden. Otherwise, │ │ │it returns FALSE. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryObjectList │Returns a pointer to an array │ │ │of HOBJECT that represents the│ │ │list of objects in the drawer.│ │ │The number of objects is │ │ │returned using parameters. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 3.2. Using Workplace Shell Objects ═══ This section describes how to: o Set objects on the Launch Pad o Create objects o Install objects - By running an installation program - By running a batch file - By using the Workplace Shell Class List Object Utility. ═══ 3.2.1. Using Launch Pads ═══ Action buttons are added to or removed from the Launch Pad by overriding wpQueryActionButtons. You must declare an instance data variable in your subclass of type PACTIONS. When overriding wpQueryActionButtons, verify if pMyActions is NULL. If it is, allocate memory to hold the parent's actions and the ones you are adding. Copy the parent's actions to your array, add yours, and then return, as shown in the following sample code: SOM_Scope PACTIONS SOMLINK mylnchpd_wpQueryActionButtons( WPLaunchPad *somSelf, PULONG pulNumActions) { MyLaunchPadData *somThis = MyLaunchPadGetData(somSelf); PACTIONS pParentActions; ULONG ulParentActions; MyLaunchPadMethodDebug("MyLaunchPad","mylnchpd_wpQueryActionButtons"); if (!_pMyActions) { pParentActions = parent_wpQueryActionButtons(somSelf, &ulParentActions); _ulMyActions = ulParentActions + 1; _pMyActions = _wpAllocMem(somSelf,_ulMyActions*sizeof(ACTIONS), NULL); if (!_pMyActions) { return parent_wpQueryActionButtons(somSelf, pulNumActions); } _pMyActions[ulParentActions].pszTitle = "My new action"; _pMyActions[ulParentActions].ulMenuId = MY_MENUID; _pMyActions[ulParentActions].hIcon = myActionIcon; if (ulParentActions) { memcpy(_pMyActions, pParentActions,ulParentActions*sizeof(ACTIONS)); } } if (pulNumActions) { (*pulNumActions) = _ulMyActions; } return (PACTIONS) _pMyActions; } Note: When overriding wpQueryActionButtons you must also provide a subclass of WPDesktop, override wpMenuItemSelected, and handle the MY_MENUID action. ═══ 3.2.2. Creating Objects ═══ In order to illustrate what is required to create a complete Workplace Shell object that you can use constructively, a complete Workplace Shell SOM program is included in Sample Code for Creating Objects. The example program is a usable Workplace Shell object that provides the facility to change the normally unchangable style flags of any Desktop object dropped on it. When you drop an object onto the Workplace Shell Styler, WPSTYLER will open the Settings notebook and display a Style settings page. On this page, you will see the current styles of the object and be able to change them. Using the Workplace Shell Styler, you can change the title in addition to the following behaviors: Copy, Delete, Drag, Drop, Move, Print, Rename, Shadow and Template. The class name is called WPStyler and is derived from WPAbstract, which is derived from the WPObject root Workplace Shell Class. The implementation of the WPStyler object consists primarily of overrides to instance and class methods inherited from the WPObject and WPAbstract classes. ═══ 3.2.2.1. WPStyler Instance Methods ═══ WPStyler uses ten instance methods: o wpInitData o wpDragOver o wpDrop o wpOpen o wpAddSettingsPages o wpAddObjectWindowPage o wpAddObjectGeneralPage o InsertObjectStylePage o QueryObjectStyle o SetObjectStyle. The three last ones are new instance methods introduced by WPStyler. The following subsections provide explanations on each of them, such as why the instance method is used and whether or not it is overridden. ═══ 3.2.2.1.1. Initializing Data and Allocating Memory ═══ The wpInitData method is called when an object is created or when it is awakened from the dormant state so that it can initialize all of its instance variables to a known state. Note that this method is called before the object's state is known. Initialize instance data and allocate extra memory that you might need in this method. Any memory allocated in wpInitData should always be d eallocated in wpUnInitData, which is always called when an object is destroyed. WPStyler does not override wpUnInitData. ═══ 3.2.2.1.2. Dragging Over an Object ═══ The wpDragOver method is invoked on an object as other objects are dragged over it, to determine whether or not it can be dropped on. The wpDragOver method provides information of every object being dragged over the Styler object. The WPStyler will allow all objects to be dropped on and changed. ═══ 3.2.2.1.3. Dropping an Object ═══ Once an object is dropped onto the Workplace Shell Styler, wpDrop is called. It is, at this point, where WPStyler queries from the drag information the self pointer of the object being dropped and save it in its instance data. Once the self pointer of the object is acquired, a call to the parent wpOpen is made open the Settings notebook. ═══ 3.2.2.1.4. Opening a View of an Object ═══ The wpOpen method is called to open a view of this object. The ulView parameter tells the object whether to open the Settings view, Contents view, or Help view (and so on), and param is an optional parameter. Note that both parameters can be zero, in which case the default view of the object is opened. This instance method is invoked when a user either double clicks on the object or selects the Settings item from the pop-up menu. When wpOpen is called as a result of the user selecting the Open item or clicking on the object, WPStyler will display a usage message box. OPEN_STYLER is returned as the default view to the Open item, because wpQueryDefaultView is subclasses and the Styler's ID is returned as the default view. ═══ 3.2.2.1.5. Adding the Styler Page to the Settings Notebook ═══ The wpAddSettingsPages method allows each object class to insert its own settings pages into the Settings notebook for an object. WPStyler introduces the InsertObjectStylePage instance method. InsertObjectStylePage is called from the wpAddSettingsPages override to insert the new dialog page into the existing Workplace Shell Settings notebook. InsertObjectStylePage simply fills the PAGEINFO data structure to point to the Styler dialog window and procedure, and it then inserts that page into the notebook by calling wpInsertSettingsPage. InsertObjectStylePage is called only if the notebook is opened for an object that was dropped on the Styler. This method is not called when displaying the Settings notebook for WPStyler. ═══ 3.2.2.1.6. Removing the Window Page from the Settings Notebook ═══ The wpAddObjectWindowPage method adds the standard Window page to the Settings notebook. WPStyler overrides this method to remove the Window page from the Settings notebook. All WPAbstract objects have a Window page, but as it has no meaning for WPStyler, it will return SETTINGS_PAGE_REMOVED so that this page is not inserted when the notebook is created. ═══ 3.2.2.1.7. Removing the General Page from the Settings Notebook ═══ The wpAddObjectGeneralPage method adds the standard Icon page to the Settings notebook. This method is overridden so that the Icon page is removed when displaying the styles of an object. This way, when displaying the Settings notebook for the Styler, only its parent needs to be called. ═══ 3.2.2.1.8. Obtaining the Current Style ═══ QueryObjectStyle is a new instance method introduced by WPStyler. QueryObjectStyle calls wpQueryStyle to query the current style of the object that was dropped onto the Styler, and it then sets the Styler page checkbox and title text to reflect the current state of the object. ═══ 3.2.2.1.9. Setting the Object's Style ═══ SetObjectStyle is a new instance method introduced by WPStyler. SetObjectStyle queries the current state of the dialog checkboxes and then sets the style of the dropped object accordingly, using wpSetStyle to set the style of the object and wpSaveDeferred to save that state permanently back to the system .INI file. SetObjectStyle also queries and sets the title text of the object. ═══ 3.2.2.2. WPStyler Class Methods ═══ WPStyler uses six class methods: o wpclsInitData o wpclsQueryIcon o wpclsQueryStyle o wpclsQueryDefaultHelp o wpQueryDefaultView o clsQueryModuleHandle. The last one is a new class method introduced by WPStyler. The following subsections provide explanations on each of them, such as why the class method is used and whether or not it is overridden. ═══ 3.2.2.2.1. Initializing Data and Allocating Memory ═══ The wpclsInitData method is called when an object class is instantiated. WPStyler first calls its parent, and it then locates the class file by class name so that it can query the module handle and save it as class data. WPStyler also loads and saves a pointer to its Desktop icon. If any class data is allocated in wpclsInitData, then you should override wpclsUnInitData to free that data when the class is destroyed. ═══ 3.2.2.2.2. Obtaining the Default Icon ═══ The wpclsQueryIcon method sets the default icon to the Styler icon and resource linked into the application. The pointer handle queried during the creation of the Styler object is returned. ═══ 3.2.2.2.3. Obtaining the Class Style ═══ The wpclsQueryStyle method is called to return the class attributes for this object class: Class Style Name Description CLSSTYLE_NEVERCOPY The object cannot be copied. CLSSTYLE_NEVERDELETE The object cannot be deleted. CLSSTYLE_NEVERMOVE The object cannot be moved. CLSSTYLE_NEVERTEMPLATE This class does not have a template. Also, the Styler object will not have a Create another item in its context menu. Classes should override this method to get special behavior. ═══ 3.2.2.2.4. Setting the Default Help ═══ Override wpclsQueryDefaultHelp to set the help library name and default help ID. ═══ 3.2.2.2.5. Setting the Default View ═══ WPStyler overrides wpQueryDefaultView to set the default view for the Styler object. By returning OPEN_STYLER as the default view, a request to Open the object will cause wpOpen to be called with OPEN_STYLER. ═══ 3.2.2.2.6. Obtaining the Module Handle ═══ The clsQueryModuleHandle method returns the module handle for the WPStyler class. To avoid using globals, the WPStyler class' module handle is saved as part of its class data. This means that a new class method needs to be implemented, so that the new instance methods can gain access to it. ═══ 3.2.2.3. WPStyler Dialog Window Procedure ═══ DialogProc is registered with the dialog window when the Styler page is inserted into the Settings notebook. The dialog procedure gets control when the Styler page is given focus. The dialog procedure catches all WM_FOCUSCHANGE messages to provide an information message for each control on the Styler settings page. As the user tabs between each control on the Styler page, an information message describing the control is displayed just above the push buttons. An Apply push button is provided so that a user can apply the changes instantly without closing the Styler page. ═══ 3.2.2.4. WPStyler Functions ═══ WPStyler uses two MLE functions: o MLEImportText: This function imports text into an MLE window. o MLEExportText: This function exports text from an MLE window. ═══ 3.2.3. Installing Workplace Shell Objects ═══ Workplace Shell objects can be installed on the Desktop in two ways: o By running an installation program or batch file o By using the Workplace Shell Class Object List Utility. ═══ 3.2.3.1. Running an Installation Program ═══ You can provide installation programs for your objects. An installation program is responsible for: o Copying the DLL that contains the object's class definition from a diskette to the \OS2\DLL directory or to a directory in the LIBPATH. o Registering the class and its DLL name with the Workplace Shell by calling WinRegisterObjectClass. o Creating an object instance of the class and placing it on the Desktop or in a particular folder by calling WinCreateObject. An example of an installation program for a Workplace Shell object is shown in the following sample code: /* Command-line program to install Workplace Shell objects */ #define INCL_WINWORKPLACE #include #include #include #if defined(DEBUG) #define LOCATION_DESKTOP ((PSZ)"") #endif /* * Main Function * * argv[1] = Class Name * argv[2] = Module (DLL) Name * argv[3] = Object Title * argv[4] = Location * argv[5] = Setup String */ INT main (argc, argv) INT argc; CHAR *argv[]; { HAB vhab; HMQ vhmq; BOOL fSuccess; if (argc == 1) { #if defined(DEBUG) { printf("Usage:\n\n"); printf(" WPCREATE ClassName ModuleName Title [[Location] [SetupString]]\n"); } #endif return (0); } /* End if (argc == 1) */ if (argc < 4) return (1); /* First three parms are mandatory */ /* Register the class */ #if defined(DEBUG) printf("WinRegisterObjectClass(%s, %s)...\n", argv[1], argv[2]); #endif fSuccess = WinRegisterObjectClass( argv[1], /* Class name (case sensitive) */ argv[2]); /* Module name */ if (!fSuccess) return (1); /* Return non-zero for error */ #if defined(DEBUG) printf("Success: rc = %u\n", fSuccess); #endif /* Create an instance of the object */ #if defined(DEBUG) printf("WinCreateObject(%s, %s,...)...\n", argv[1], argv[3]); #endif fSuccess = WinCreateObject( argv[1], /* Class name */ argv[3], /* Object title */ argc > 5 ? argv[5] : " ", /* Setup string */ argc > 4 ? argv[4] : LOCATION_DESKTOP, /* Location */ CO_FAILIFEXISTS); /* Flags */ if (!fSuccess) return (1); /* Return non-zero for error */ #if defined(DEBUG) printf("Success: rc = %u\n", fSuccess); #endif return(0); } /* End main() */ Instantiating an object is an optional responsibility of an installation program. When a class is registered by calling WinRegisterObjectClass, an object template is placed in the Templates folder on the Desktop, if the class supports templating. Users can create instances of these objects by tearing off a copy of the template. This can be useful for larger applications that define data-file objects that are associated with program objects. ═══ 3.2.3.2. Running an Installation Batch File ═══ An installation batch file written in the REXX language performs the same operations but uses the following REXX-language utility functions: REXX Functions Workplace Shell Methods SysCreateObject WinCreateObject SysRegisterObjectClass WinRegisterObjectClass SysDeRegisterObjectClass WinDeregisterObjectClass An example of an installation batch file written using the REXX-language utility methods is shown in the following sample code: /* Register a Workplace Shell class and create an instance */ /* Load the REXX utility functions */ call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' call SysLoadFuncs /* Register the class with the Workplace Shell */ if SysRegisterObjectClass("NewObjectClass", "NEWDLL") then say 'Class Registration successfully completed for the NewObject' /* Create an instance of the object */ if SysCreateObject("NewObjectClass", "A New Object", "", "OBJECTID=") then say 'A New Object successfully created and placed on Desktop' ═══ 3.2.3.3. Using the Workplace Shell Class List Object Utility ═══ The Toolkit provides a Workplace Shell Class List Object that is automatically installed during the installation of the Toolkit. This object is a tool that provides a windowed user interface for general Workplace Shell class registration and object creation activities. It performs all the methods that a typical Workplace Shell object installation program must provide, with the exception of copying files from an installation diskette to a hard disk. It is a fast and easy way to build and test objects in an application development environment. The Workplace Shell Class List Object Utility displays a hierarchical list of all classes registered with the Workplace Shell. You can add a class to this list or perform a number of actions on a specific class in the list. You can also create an instance of the class, replace and unreplace the class, and delete the class. The Workplace Shell Class List Object Utility uses WinEnumObjectClasses to get the list of all classes registered with the Workplace Shell. WinEnumObjectClasses returns only the name of the class and the DLL module that contains the class definition. It does not return information on the class ancestry that can be used to construct a hierarchical list of classes. Because the Workplace Shell Class List Object Utility is a Workplace Shell object, it can call the somParent function to determine parentage of each class and use this information to construct the list. The Workplace Shell Class List Object Utility uses the following methods: Method Name Description WinCreateObject To create objects. WinRegisterObjectClass To register object classes. WinDeregisterObjectClass To deregister object classes. WinReplaceObjectClass To replace object classes. Note: This tool can be used to delete any Workplace Shell class other than the predefined Workplace Shell classes provided with the OS/2 operating system Version 2.0. You should understand Workplace Shell classes and how they are defined so that they can be recovered. Because the general user may not have this level of understanding, you should not distribute this tool with their objects to the users. The recommended way of delivering objects to them is through installation programs or batch files. ═══ 3.3. Sample Code for Creating Objects ═══ In order to illustrate what is required to create a complete Workplace Shell object that you can use constructively, a complete Workplace Shell SOM program is included here. The example program is a usable Workplace Shell object that provides the facility to change the normally unchangable style flags of any Desktop object dropped on it. When you drop an object onto the Workplace Shell Styler, WPSTYLER will open the Settings notebook and display a Style settings page, as shown in the following figure: On this page, you will see the current styles of the object and be able to change them. Using the Workplace Shell Styler, you can change the title in addition to the following behaviors: o Copy o Delete o Drag o Drop o Move o Print o Rename o Shadow o Template. The Workplace Shell Styler sample demonstrates the basic steps you need to do to create a Workplace Shell object: o Create a simple Workplace Shell SOM program o Create a custom Settings notebook page o Add a custom page to the Settings notebook o Remove unwanted pages from the Settings notebook o Open the Settings notebook o Implement a custom help for the help push button o Implement the Pickup and Drop operation in your object o Manipulate object styles and change their title text. The class name is called WPStyler and is derived from WPAbstract, which is derived from the WPObject root Workplace Shell Class. This means that WPStyler inherits the methods from WPAbstract, which, in turn, inherits all of the instance and class methods from WPObject. The implementation of the WPStyler object consists primarily of overrides to instance and class methods inherited from the WPObject and WPAbstract classes. ═══ 3.3.1. Creating Objects Application Sample Code ═══ Several parts of this program are explained in Creating Objects. The WPStyler application includes the following files: File Name Description WPSTYLER.IDL Class interface definition WPSTYLER.C Source code WPSTYLER.RCH Resource header WPSTYLER.RC Resource code WPSTYLER.IPF Styler help source WPSTYLER.MAK Styler makefile for building the application. ═══ 3.3.1.1. Class Definition File for Styler ═══ The following sample illustrates the class interface definition file (IDL): #ifndef wpstyler_idl #define wpstyler_idl #include #include interface M_Styler; interface Styler : WPAbstract { ULONG InsertObjectStylePage(in HWND hwndDlg); // Override: InsertObjectStylePage // // Description: // Insert the Styler page into the Settings notebook. ULONG QueryObjectStyle(in HWND hwndDlg); // Override: QueryObjectStyle // // Description: // Query the object's title and current style. // Set the Styler Settings page checkboxes and MLE. VOID SetObjectStyle(in HWND hwndDlg); // Override: SetObjectStyle // // Description: // Query the current checkbox state and set // the object's style accordingly. #ifdef __SOMIDL__ implementation { releaseorder: InsertObjectStylePage,QueryObjectStyle,SetObjectStyle; /* * Class modifiers */ functionprefix = Sty_; majorversion = 1; minorversion = 2; filestem = wpstyler; metaclass = M_Styler; callstyle = oidl; dllname = "wpstyler.dll"; /* * Internal instance variables */ BOOL fGeneralPage; // Display the General page if true ULONG ulStyle; // Save the style flags WPObject self; // Save the self pointer of dropped object /* * Passthru to the .IH file the following: */ passthru C_ih = "#define INCL_PM" "#define INCL_DOS" "#define INCL_DEV" "#define INCL_WPCLASS" "#define INCL_WINWORKPLACE" "#include " "#include " "#include " "#include \"wpstyler.rch\"" "#include " "" "#define OPEN_STYLER (OPEN_USER+1)" "" "#define MPNULL (MPFROMP(NULL))" "#define MPZERO (MPFROMSHORT(0))" "#define MRTRUE (MRFROMSHORT((SHORT) TRUE))" "#define MRFALSE (MRFROMSHORT((SHORT) FALSE))" "" "#define BM_UNCHECKED 0 // Parms in BM_SETCHECK message" "#define BM_CHECKED 1 // to set or clear the radio buttons" "" "#define PMWinSetDlgItemChecked(hwnd, id, bCheck)\" " (WinSendDlgItemMsg((hwnd), (id), BM_SETCHECK,\" " ((bCheck) ? MPFROMSHORT(1) : MPZERO), MPNULL))" "" "#define PMWinIsDlgItemChecked(hwnd, id)\" " (SHORT1FROMMR(WinSendDlgItemMsg((hwnd), (id),\" " BM_QUERYCHECK, MPNULL, MPNULL)) != 0)" "" "#define WinSetDialogFont(hwnd, usId, szFont)\" " (WinSetPresParam(WinWindowFromID(hwnd, usId),\" " PP_FONTNAMESIZE, (ULONG) strlen(szFont)+1, szFont))" ""; /* * Method modifiers */ wpInitData: override; // Override: wpInitData // // Description: // Initialize the state variables. Allocate any extra // memory that WPStyler might need. wpDragOver: override; // Method: wpDragOver // // Description: // Allow any object to be dropped on the Styler. wpDrop: override; // Method: wpDrop // // Description: // Query the self pointer of dropped object. // Call wpOpen to open the Settings notebook // and display the styles. wpOpen: override; // Method: wpOpen // // Description: // Opens the Settings notebook to display the General page // for the Styler object. wpAddSettingsPages: override; // Method: wpAddSettingsPages // // Description: // Add the Styler Settings page to let the user alter // the styles of any object that is dropped onto us. wpAddObjectWindowPage: override; // Method: wpAddObjectWindowPage // // Description: // Remove the Window page. wpAddObjectGeneralPage: override; // Method: wpAddObjectGeneralPage // // Description: // Remove the General page when the Styler // page is displayed. }; #endif /* __SOMIDL__ */ }; interface M_Styler : M_WPAbstract { HMODULE clsQueryModuleHandle(); // Method: clsQueryModuleHandle // // Description: // Return the module handle. #ifdef __SOMIDL__ implementation { releaseorder: clsQueryModuleHandle; /* * Class modifiers */ functionprefix = StyM_; majorversion = 1; minorversion = 2; filestem = wpstyler; callstyle = oidl; dllname = "wpstyler.dll"; /* * Internal instance variables */ HMODULE hmod; /* Resource module handle */ HPOINTER hicon; /* Icon handle */ /* * Method modifiers */ wpclsInitData: override; // Method: wpclsInitData // // Description: // Initalize the class data, query and save the module handle. // Load the icon handle. wpclsQueryIcon: override; // Method: wpclsQueryIcon // // Description: // Set the Stylers icon handle. wpclsQueryStyle: override; // Method: wpclsQueryStyle // // Description: // wpclsQueryStyle is called to allow the class object to // specify the default object class style for its instances. // // Remarks: // This method can be called at any time in order to determine the // default style for instances of this class. // This method should be overridden in order to modify the default // object style for instances of this class. wpclsQueryDefaultHelp: override; // Method: wpclsQueryDefaultHelp // // Description: // Set the help library name and default help ID. wpclsQueryDefaultView: override; // Method: wpclsQueryDefaultView // // Description: // Return the default view for a new instance of this object. // Tell the system what the Styler's default view is. }; #endif /* __SOMIDL__ */ }; #endif /* wpstyler_idl */ ═══ 3.3.1.2. Source Code for Styler ═══ The following sample illustrates the source code (C): /* * File.....: WPSTYLER.C * * Purpose..: Workplace Shell Object Styler. * * Instance Methods...: * Sty_InsertObjectStylePage() * Sty_QueryObjectStyle() * Sty_SetObjectStyle() * Sty_wpInitData() * Sty_wpDragOver() * Sty_wpDrop() * Sty_wpOpen() * Sty_wpAddSettingsPages() * Sty_wpAddObjectWindowPage() * Sty_wpAddObjectGeneralPage() * * Class Methods...: * StyM_clsQueryModuleHandle() * StyM_wpclsInitData() * StyM_wpclsQueryIcon() * StyM_wpclsQueryStyle() * StyM_wpclsQueryDefaultHelp() * StyM_wpclsQueryDefaultView() * * Dialog Procedures and Functions...: * DialogProc() * MLEImportText() * MLEExportText() */ #pragma comment(compiler) #pragma info(nogen) #define Styler_Class_Source #define M_Styler_Class_Source #include "wpstyler.ih" /* * Prototype local functions used */ MRESULT EXPENTRY DialogProc(HWND, ULONG, MPARAM, MPARAM); ULONG EXPENTRY MLEImportText(HWND, CHAR *, ULONG); APIRET EXPENTRY MLEExportText(HWND, PSZ *); CHAR szHelpLibrary[] = "wpstyler.hlp"; /* * Override: InsertObjectStylePage * * Description: * Insert the Style page into the Settings notebook */ SOM_Scope ULONG SOMLINK Sty_InsertObjectStylePage(Styler *somSelf, HWND hwndDlg) { PAGEINFO pi; /* StylerData *somThis = StylerGetData(somSelf); */ StylerMethodDebug("Styler", "Sty_InsertObjectStylePage"); memset((PCH) &pi, 0, sizeof(PAGEINFO)); pi.cb = sizeof(PAGEINFO); pi.hwndPage = NULLHANDLE; pi.usPageStyleFlags = BKA_MAJOR; pi.usPageInsertFlags = BKA_FIRST; pi.pfnwp = DialogProc; pi.resid = _clsQueryModuleHandle(_Styler); pi.dlgid = DLG_STYLE; pi.pszName = "~Style"; pi.pCreateParams = somSelf; pi.pszHelpLibraryName = szHelpLibrary; return _wpInsertSettingsPage(somSelf, hwndDlg, &pi); } /* * Override: QueryObjectStyle * * Description: * Query the object's title and current style. * Set the Styler Settings page checkboxes and MLE. */ SOM_Scope ULONG SOMLINK Sty_QueryObjectStyle(Styler *somSelf, HWND hwndDlg) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_QueryObjectStyle"); /* * Query and set the object's name in the notebook page */ MLEImportText(WinWindowFromID(hwndDlg, DLG_OBJECTNAME), _wpQueryTitle(_self), 0); /* * Query the object's current state */ _ulStyle = _wpQueryStyle(_self); PMWinSetDlgItemChecked(hwndDlg, DLG_COPY, _ulStyle & OBJSTYLE_NOCOPY ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_SHADOW, _ulStyle & OBJSTYLE_NOLINK ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_DELETE, _ulStyle & OBJSTYLE_NODELETE ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_DRAG, _ulStyle & OBJSTYLE_NODRAG ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_DROP, _ulStyle & OBJSTYLE_NODROP ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_SETTINGS, _ulStyle & OBJSTYLE_NOSETTINGS ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_MOVE, _ulStyle & OBJSTYLE_NOMOVE ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_PRINT, _ulStyle & OBJSTYLE_NOPRINT ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_RENAME, _ulStyle & OBJSTYLE_NORENAME ? BM_UNCHECKED : BM_CHECKED); PMWinSetDlgItemChecked(hwndDlg, DLG_TEMPLATE, _ulStyle & OBJSTYLE_TEMPLATE ? BM_CHECKED : BM_UNCHECKED); return _ulStyle; } /* * Override: SetObjectStyle * * Description: * Query the current checkbox state and set the style of the * object accordingly. */ SOM_Scope void SOMLINK Sty_SetObjectStyle(Styler *somSelf, HWND hwndDlg) { PSZ pszName; StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_SetObjectStyle"); /* * NOCOPY: This object cannot be copied */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_COPY)) _ulStyle &= ~OBJSTYLE_NOCOPY; else _ulStyle |= OBJSTYLE_NOCOPY; /* * NOSHADOW: This object cannot have a shadow created */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_SHADOW)) _ulStyle &= ~OBJSTYLE_NOLINK; else _ulStyle |= OBJSTYLE_NOLINK; /* * NODELETE: This object cannot be deleted */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_DELETE)) _ulStyle &= ~OBJSTYLE_NODELETE; else _ulStyle |= OBJSTYLE_NODELETE; /* * NODRAG: This object cannot be dragged */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_DRAG)) _ulStyle &= ~OBJSTYLE_NODRAG; else _ulStyle |= OBJSTYLE_NODRAG; /* * NODROP: No other object can be dropped on this object. * However, object can be dragged and dropped on other objects. */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_DROP)) _ulStyle &= ~OBJSTYLE_NODROP; else _ulStyle |= OBJSTYLE_NODROP; /* * NODRAG: This object cannot be moved */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_MOVE)) _ulStyle &= ~OBJSTYLE_NOMOVE; else _ulStyle |= OBJSTYLE_NOMOVE; /* * NOPRINT: This object cannot be printed */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_PRINT)) _ulStyle &= ~OBJSTYLE_NOPRINT; else _ulStyle |= OBJSTYLE_NOPRINT; /* * NORENAME: This object cannot be renamed */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_RENAME)) _ulStyle &= ~OBJSTYLE_NORENAME; else _ulStyle |= OBJSTYLE_NORENAME; /* * NOTEMPLATE: This object is a template */ if (PMWinIsDlgItemChecked(hwndDlg, DLG_TEMPLATE)) _ulStyle |= OBJSTYLE_TEMPLATE; else _ulStyle &= ~OBJSTYLE_TEMPLATE; /* * Extract and set the title text */ MLEExportText(WinWindowFromID(hwndDlg, DLG_OBJECTNAME), &pszName); _wpSetTitle(_self, pszName); free(pszName); /* * Set the object's new style and save the state to the .INI file */ _wpSetStyle(_self, _ulStyle); _wpSaveDeferred(_self); } /* * Override: wpInitData * * Description: * Initialize the state variables. Allocate any extra * memory that WPStyler might need. */ SOM_Scope void SOMLINK Sty_wpInitData(Styler *somSelf) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_wpInitData"); _self = (WPObject *) 0; parent_wpInitData(somSelf); } /* * Method: wpDragOver * * Description: * Allow any object to be dropped on the Styler */ SOM_Scope MRESULT SOMLINK Sty_wpDragOver(Styler *somSelf, HWND hwndCnr, PDRAGINFO pdrgInfo) { BOOL fSuccess; PDRAGITEM pditem; // Drag item pointer /* StylerData *somThis = StylerGetData(somSelf); */ StylerMethodDebug("Styler", "Sty_wpDragOver"); pditem = DrgQueryDragitemPtr(pdrgInfo, 0); if (pditem == NULL) DosBeep(500, 100); fSuccess = DrgVerifyRMF(pditem, "DRM_OBJECT", NULL); if (fSuccess) return MRFROM2SHORT(DOR_DROP, DO_COPY); else return MRFROM2SHORT(DOR_NEVERDROP, DO_COPY); } /* * Method: wpDrop * * Description: * Query the self pointer of the dropped object. * Call wpOpen to open the Settings notebook and display the styles. */ SOM_Scope MRESULT SOMLINK Sty_wpDrop(Styler *somSelf, HWND hwndCnr, PDRAGINFO pdrgInfo, PDRAGITEM pdrgItem) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_wpDrop"); /* * Query for the dropped object's self pointer. */ _self = OBJECT_FROM_PREC(pdrgItem->ulItemID); /* * Call the parents wpOpen to display the Settings notebook */ _fGeneralPage = FALSE; parent_wpOpen(somSelf, NULLHANDLE, OPEN_SETTINGS, 0L); return parent_wpDrop(somSelf, hwndCnr, pdrgInfo, pdrgItem); } /* * Method: wpOpen * * Description: * Opens the Settings notebook to display the General * page for the Styler object. */ SOM_Scope HWND SOMLINK Sty_wpOpen(Styler *somSelf, HWND hwndCnr, ULONG ulView, ULONG param) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_wpOpen"); switch(ulView) { case OPEN_SETTINGS: _fGeneralPage = TRUE; break; case OPEN_STYLER: { /* * If the user double clicks on the Styler object, present a * message box instead of openning the Settings page. */ WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Drop an object on the Workplace Shell Object " "Styler to change the style state of that object.", "Workplace Shell Object Styler", 0, MB_OK | MB_APPLMODAL | MB_MOVEABLE); break; } default: break; } return parent_wpOpen(somSelf, hwndCnr, ulView, param); } /* * Method: wpAddSettingsPages * * Description: * Add the Styler Settings page to let the user alter the styles * of any object that is dropped onto us. */ SOM_Scope BOOL SOMLINK Sty_wpAddSettingsPages(Styler *somSelf, HWND hwndNotebook) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler", "Sty_wpAddSettingsPages"); parent_wpAddSettingsPages(somSelf, hwndNotebook); /* * Insert the user page into the Settings notebook */ if (!_fGeneralPage) _InsertObjectStylePage(somSelf, hwndNotebook); return TRUE; } /* * Method: wpAddObjectWindowPage * * Description: * Remove the Window page */ SOM_Scope ULONG SOMLINK Sty_wpAddObjectWindowPage(Styler *somSelf, HWND hwndNotebook) { /* StylerData *somThis = StylerGetData(somSelf); */ StylerMethodDebug("Styler", "Sty_wpAddObjectWindowPage"); return SETTINGS_PAGE_REMOVED; } /* * Method: wpAddObjectGeneralPage * * Description: * Remove the General page when displaying the Styler page */ SOM_Scope ULONG SOMLINK Sty_wpAddObjectGeneralPage(Styler *somSelf, HWND hwndNotebook) { StylerData *somThis = StylerGetData(somSelf); StylerMethodDebug("Styler","Sty_wpAddObjectGeneralPage"); return _fGeneralPage ? parent_wpAddObjectGeneralPage(somSelf, hwndNotebook) : SETTINGS_PAGE_REMOVED; } /* * Method: wpclsQueryDefaultHelp * * Description: * Set the help library name and default help ID */ SOM_Scope BOOL SOMLINK StyM_wpclsQueryDefaultHelp(M_Styler *somSelf, PULONG pHelpPanelId, PSZ pszHelpLibrary) { /* M_StylerData *somThis = M_StylerGetData(somSelf); */ M_StylerMethodDebug("M_Styler","StyM_wpclsQueryDefaultHelp"); if (pHelpPanelId) *pHelpPanelId = ID_HELP_STYLER; if (pszHelpLibrary) strcpy(pszHelpLibrary, szHelpLibrary); return TRUE; } /* * Method: clsQueryModuleHandle * * Description: * Return the module handle */ SOM_Scope HMODULE SOMLINK StyM_clsQueryModuleHandle(M_Styler *somSelf) { M_StylerData *somThis = M_StylerGetData(somSelf); M_StylerMethodDebug("M_Styler", "StyM_clsQueryModuleHandle"); return (HMODULE) _hmod; } /* * Method: wpclsInitData * * Description: * Initalize the class data, query and save the module handle. * Load the icon handle. */ SOM_Scope void SOMLINK StyM_wpclsInitData(M_Styler *somSelf) { PSZ psz; somId stylerId; M_StylerData *somThis = M_StylerGetData(somSelf); M_StylerMethodDebug("M_Styler", "StyM_wpclsInitData"); parent_wpclsInitData(somSelf); stylerId = somIdFromString("Styler"); psz = _somLocateClassFile(SOMClassMgrObject, stylerId, Styler_MajorVersion, Styler_MinorVersion); SOMFree(stylerId); if (psz != NULL) DosQueryModuleHandle(psz, &_hmod); /* * Load the icon and store it in the class data */ _hicon = WinLoadPointer(HWND_DESKTOP, _hmod, ID_OBJECTICON); } /* * Method: wpclsQueryIcon * * Description: * Set the Styler's icon handle */ SOM_Scope HPOINTER SOMLINK StyM_wpclsQueryIcon(M_Styler *somSelf) { M_StylerData *somThis = M_StylerGetData(somSelf); M_StylerMethodDebug("M_Styler", "StyM_wpclsQueryIcon"); return _hicon; } /* * Method: wpclsQueryStyle * * Description: * wpclsQueryStyle is called to allow the class object to * specify the default object class style for its instances. * * Remarks: * This method can be called at any time in order to determine the * default style for instances of this class. * This method should be overridden in order to modify the default * object style for instances of this class. */ SOM_Scope ULONG SOMLINK StyM_wpclsQueryStyle(M_Styler *somSelf) { /* M_StylerData *somThis = M_StylerGetData(somSelf); */ M_StylerMethodDebug("M_Styler","StyM_wpclsQueryStyle"); return parent_wpclsQueryStyle(somSelf) | CLSSTYLE_NEVERTEMPLATE; } /* * Method: wpclsQueryDefaultView * * Description: * Return the default view for a new instance of this object. * Tell the system what the Styler's default view is. */ SOM_Scope ULONG SOMLINK StyM_wpclsQueryDefaultView(M_Styler *somSelf) { /* M_StylerData *somThis = M_StylerGetData(somSelf); */ M_StylerMethodDebug("M_Styler", "StyM_wpclsQueryDefaultView"); return OPEN_STYLER; } typedef struct _WINDATA { SOMAny *somSelf; StylerData *somThis; BOOL fClose; } WINDATA, *PWINDATA; /* * Dialog window Procedure */ MRESULT EXPENTRY DialogProc(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2) { MRESULT mresultWpRtnCd = MRFALSE; PWINDATA pwin = (PWINDATA) WinQueryWindowPtr(hwndDlg, QWL_USER); switch(msg) { case WM_INITDLG: { pwin = (PWINDATA) _wpAllocMem((SOMAny *) mp2, sizeof(WINDATA), NULL); WinSetWindowPtr(hwndDlg, QWL_USER, pwin); /* * Initialize the WINDATA data structure */ pwin->somSelf = (SOMAny *) mp2; pwin->somThis = StylerGetData(pwin->somSelf); pwin->fClose = FALSE; /* * Query the style of the object and set the checkboxes */ _QueryObjectStyle(pwin->somSelf, hwndDlg); /* * Set the status line font size */ WinSetDialogFont(hwndDlg, DLG_STATUS, "8.Helv"); /* * Return TRUE to tell PM that focus has changed */ mresultWpRtnCd = (MRESULT) TRUE; break; } /* End of case WM_INITDLG */ case WM_FOCUSCHANGE: { HWND hwndFocus = HWNDFROMMP(mp1); mresultWpRtnCd = WinDefDlgProc(hwndDlg, msg, mp1, mp2); /* * When mp2 is FALSE, then hwndFocus is the * control window that is receiving focus */ if (SHORT1FROMMP(mp2)) break; /* Title text MLE */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_OBJECTNAME)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Change the title of the object"); break; } else /* Apply push button */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_APPLY)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Save all changes to the system .INI file"); break; } else /* Undo push button */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_UNDO)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Undo all changes made since last apply"); break; } else /* Cancel push button */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_CANCEL)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Cancel processing the current object"); break; } else /* Help push button */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_HELP)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Display the user help for Styler"); break; } else /* Copy checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_COPY)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow the object to be copied"); break; } else /* Delete checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_DELETE)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Make object deletable"); break; } else /* Drag checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_DRAG)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow the object to be dragged"); break; } else /* Drop checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_DROP)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow objects to be drop on object"); break; } else /* Settings checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_SETTINGS)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Settings checkbox"); break; } else /* Move checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_MOVE)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow this object to be moved"); break; } else /* Print checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_PRINT)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Make object printable"); break; } else /* Template checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_TEMPLATE)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Make a template from the object"); break; } else /* Rename checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_RENAME)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow the object to be renamed"); break; } else /* Shadow checkbox */ if (hwndFocus == WinWindowFromID(hwndDlg, DLG_SHADOW)) { WinSetDlgItemText(hwndDlg, DLG_STATUS, "Allow the object to be shadowed"); break; } else { WinSetDlgItemText(hwndDlg, DLG_STATUS, ""); } break; } /* End of case WM_FOCUSCHANGE */ case WM_COMMAND: { switch(SHORT1FROMMP(mp1)) { case DLG_APPLY: /* Apply push button */ { _SetObjectStyle(pwin->somSelf, hwndDlg); // Save state to the .INI file now! _wpSaveImmediate(pwin->somSelf); WinSetDlgItemText(hwndDlg, DLG_STATUS, "Changes applied to object"); break; } case DLG_UNDO: /* Undo push button */ { _QueryObjectStyle(pwin->somSelf, hwndDlg); WinSetDlgItemText(hwndDlg, DLG_STATUS, "Changes undone"); break; } case DLG_CANCEL: /* Cancel push button */ { pwin->fClose = TRUE; WinPostMsg(WinQueryWindow(hwndDlg, QW_OWNER), WM_CLOSE, 0L, 0L); break; } case DLG_HELP: /* Help push button */ { _wpDisplayHelp(pwin->somSelf, ID_HELP_STYLER, szHelpLibrary); break; } default: break; } break; } /* End of case WM_COMMAND */ case WM_DESTROY: { /* * Set the style of the object from the checkbox settings */ if (!pwin->fClose) _SetObjectStyle(pwin->somSelf, hwndDlg); _wpFreeMem(pwin->somSelf, (PBYTE) pwin); mresultWpRtnCd = WinDefDlgProc(hwndDlg, msg, mp1, mp2); } /* End of case WM_DESTROY */ default: { mresultWpRtnCd = WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; } // End of default: } return mresultWpRtnCd; } /* * Function: MLEImportText * * Description: * Import the text into an MLE window. */ ULONG EXPENTRY MLEImportText(HWND hwndMLE, CHAR *pText, ULONG ulSize) { ULONG ulLen = ulSize; ULONG cch; LINE lBegin = 0; IPT lOffset = 0; WinSendMsg(hwndMLE, MLM_DISABLEREFRESH, 0L, 0L); /* * Get the current number of characters in the MLE box * then send a message to delete them */ cch = (ULONG) WinSendMsg(hwndMLE, MLM_QUERYTEXTLENGTH, 0L, 0L); WinSendMsg(hwndMLE, MLM_DELETE, MPFROMLONG(lBegin), MPFROMLONG(cch)); if (pText) { if (ulLen <= 0L) ulLen = (ULONG) strlen(pText); WinSendMsg(hwndMLE, MLM_SETIMPORTEXPORT, MPFROMP(pText), MPFROMSHORT((SHORT) ulLen)); cch = (ULONG) WinSendMsg(hwndMLE, MLM_IMPORT, MPFROMP(&lOffset), MPFROMP(&ulLen)); } WinSendMsg(hwndMLE, MLM_ENABLEREFRESH, 0L, 0L); return cch; } /* End of Function: MLEImportText() */ /* * Function: MLEImportText * * Description: * Export the text from an MLE window. */ APIRET EXPENTRY MLEExportText(HWND hwndMLE, PSZ *pBuf) { APIRET apiRtnCd = 0; LONG cch; LONG cchnl; IPT lOffset = 0; LONG cbChar = -1; CHAR *ptr; *pBuf = (CHAR *) NULL; /* * Get the length of the data field. * Query text length using the selected format. */ cch = (ULONG) WinSendMsg(hwndMLE, MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(lOffset), MPFROMLONG(cbChar)); if (cch > 0L) { if ((ptr = (CHAR *) malloc((USHORT) (cch + 1L))) == (CHAR *) NULL) return PMERR_MEMORY_ALLOCATION_ERR; /* * Get the text from the MLE window. */ *pBuf = ptr; WinSendMsg(hwndMLE, MLM_SETIMPORTEXPORT, MPFROMP(ptr), MPFROMSHORT(cch)); cchnl = (ULONG) WinSendMsg(hwndMLE, MLM_EXPORT, MPFROMP(&lOffset), MPFROMP((ULONG) &cch)); *(*pBuf + cchnl) = (CHAR) NULL; } return apiRtnCd; } /* End of Function: MLEExportText() */ #pragma info(nouse) ═══ 3.3.1.3. Resource Header File for Styler ═══ The following sample illustrates the resource header file (RCH): /* * Resouce header module: WPSTYLER.RCH */ #define ID_OBJECTICON 255 #define ID_HELP_STYLER 256 #define DLG_STYLE 100 #define DLG_COPY 101 #define DLG_DELETE 102 #define DLG_DRAG 103 #define DLG_DROP 104 #define DLG_SETTINGS 105 #define DLG_MOVE 106 #define DLG_PRINT 107 #define DLG_TEMPLATE 108 #define DLG_RENAME 109 #define DLG_SHADOW 110 #define DLG_OBJECTNAME 111 #define DLG_STATUS 112 #define DLG_APPLY 113 #define DLG_UNDO 114 #define DLG_CANCEL 115 #define DLG_HELP 116 ═══ 3.3.1.4. Resource Code for Styler ═══ The following sample illustrates the resource definition file (RC): /* * Resouce module: WPSTYLER.RC */ #include #include "wpstyler.rch" ICON ID_OBJECTICON WPSTYLER.ICO DLGTEMPLATE DLG_STYLE LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "", DLG_STYLE, 0, 0, 224, 200, NOT FS_DLGBORDER BEGIN /* * Create a read only MLE window on the page to hold the * object's title, similar to the General page title */ LTEXT "Title:", -1, 10, 133, 24, 8 MLE "", DLG_OBJECTNAME, 30, 111, 110, 30, MLS_WORDWRAP | WS_GROUP | MLS_IGNORETAB /* * Place all the Styler checkboxes nicely on the page */ LTEXT "Select or deselect the desired style flags", -1, 10, 101, 169, 10 AUTOCHECKBOX "~Copy", DLG_COPY, 10, 91, 80, 10 AUTOCHECKBOX "~Move", DLG_MOVE, 106, 91, 80, 10 AUTOCHECKBOX "~Delete", DLG_DELETE, 10, 77, 80, 10 AUTOCHECKBOX "~Rename", DLG_RENAME, 106, 77, 80, 10 AUTOCHECKBOX "~Shadow", DLG_SHADOW, 10, 63, 80, 10 AUTOCHECKBOX "~Print", DLG_PRINT, 106, 63, 80, 10 AUTOCHECKBOX "~Template", DLG_TEMPLATE, 10, 49, 80, 10 AUTOCHECKBOX "Dr~op", DLG_DROP, 106, 49, 80, 10 /* * Frame the Drag checkbox and set the text color to red * to bring attention to it and to warn of its danger */ CONTROL "", -1, 8, 36, 146, 11, WC_STATIC, SS_HALFTONEFRAME | WS_GROUP | WS_VISIBLE AUTOCHECKBOX "Drag (De-select with Caution)", DLG_DRAG, 10, 37, 136, 9 PRESPARAMS PP_FOREGROUNDCOLOR, 0x00FF0000L /* * Add a status line just above the push buttons */ LTEXT "", DLG_STATUS, 7, 23, 191, 10, DT_VCENTER /* * Align the push buttons along the bottom */ PUSHBUTTON "~Apply", DLG_APPLY, 7, 7, 38, 14 PUSHBUTTON "~Undo", DLG_UNDO, 57, 7, 38, 14 PUSHBUTTON "Cancel", DLG_CANCEL, 107, 7, 38, 14 PUSHBUTTON "~Help", DLG_HELP, 157, 7, 38, 14 END END ═══ 3.3.1.5. Help Source for Styler ═══ The following sample illustrates the Styler help source file (IPF): .******************************************************************* .* File Name: WPSTYLER.IPF .* Description: Information Tag Language file for help on the .* Workplace Shell Object Styler .******************************************************************* .* :userdoc. :h1 res=256 name=ID_HELP_STYLER.Workplace Shell Object Styler :i1 id=aboutStyle.Workplace Shell Object Styler :p. The Workplace Shell Object Styler is a sample Workplace Shell SOM application which demonstrates the basic functionality of a Workplace Shell SOM application. The application allows a user to change and save the basic style attributes of any object that is dropped on it. .* :note. Use this application with care, deselecting all of the items (especially the Drag) will prevent you from using WPSTYLER again in order to reinstate the styles. .* :p. :hp2.Title Bar Text:ehp2. :p. You can modify the title bar text of the object from the Workplace Shell Styler in addition to changing the object style. Changing the title text here has the same effect as changing it from the General page of the object itself. :p. :hp2.Items:ehp2. .* :ul. :li. Copy :p. Deselect this item to prevent the object from being copied. The :hp2.Copy...:ehp2. item will be removed from the pop-up menu. :li. Move :p. Deselect this item to prevent the object from being moved. The :hp2.Move...:ehp2. item will be removed from the pop-up menu. :li. Delete :p. Deselect this item to prevent the object from being deleted. The :hp2.Delete...:ehp2. item will be removed from the pop-up menu. :li. Rename :p. Deselect this item to prevent the object from being renamed. No visual change can be observed. :li. Shadow :p. Deselect this item to prevent the object from being shadowed. The :hp2.Create shadow...:ehp2. item will be removed from the pop-up menu. :li. Print :p. Deselect this item to prevent the object from being printed. The :hp2.Print...:ehp2. item will be removed from the pop-up menu. :p. The print item is normally only visible on objects that can be printed such as a document file viewed through the Drives folder. Therefore, this item will have no effect on objects such as folders. :li. Template :p. Selecting this item will change the object into a template, at which point you can only tear off objects from it. :li. Drop :p. Deselect this item to prevent objects from being dropped onto it. :li. Drag :p. Deselect this item with care. This will prevent the object from being dragged; therefore you will not be able to drag the object over the Workplace Shell Styler again to change the item back. :p. Use this item where you wish to have an object remain on the Desktop in a certain location and not give users the ability to change that location. :eul. .* :p. :hp2.Push buttons:ehp2. .* :ul. :li. Apply :p. Press this button to apply the changes immediately to the object while remaining in the Workplace Shell Styler dialog window. :li. Undo :p. Press this button to undo any of the checkboxes changed since the last apply. :li. Cancel :p. Press this button to cancel your changes and remain at the state you started at or at the state of the last apply. :note. This is different than closing the window through the :hp2.Close:ehp2. item on the system menu. The system :hp2.Close:eph2. item saves the current state of the checkboxes. :li. Help :p. This push button present this help panel. :eul. .* :euserdoc. ═══ 3.3.1.6. Make File for Styler ═══ The following sample illustrates the make file (MAK): # # Makefile module: WPSTYLER.MAK # .SUFFIXES: .c .obj .dll .idl .h .ih .rc .res SC = sc SCFLAGS = -maddstar -S128000 -C128000 -mnoint -v SCLIST = -s "ih;h;c;def" TOOLKIT = c:\toolkit IBMCPP = c:\ibmcpp INCLUDE = $(TOOLKIT)\h;$(IBMCPP)\include;.;$(INCLUDE) SMINCLUDE = S(TOOLKIT)\idl;$(INCLUDE);$(SMINCLUDE) LIB = $(TOOLKIT)\lib;$(IBMCPP)\lib;$(LIB) CFLAGS = -Ge- -Ss+ -C+ -Kb -Q+ -Ms LFLAGS = /MAP /NOL /NOI /EXEPACK:2 /PACKCODE /PACKDATA /FAR /ALIGN:4 b=wpstyler all: $(b).dll $(b).ih $(b).hlp .c.obj: icc $(CFLAGS) $*.c $(b).dll: $(b).ih $(b).obj $(b).def $(b).res link386 $(b) $(LFLAGS), $(b).dll, $(b).map, somtk, $(b) rc $(b).res $(b).dll mapsym $(b).map $(b).obj: $(b).c $(b).h $(b).res: $(b).rc $(b).ico rc -r $(b).rc $(b).ih: $(b).idl $(SC) $(SCFLAGS) $(SCLIST) $(@B).idl $(b).hlp: $(b).ipf ipfc $(b).ipf clean: -del $(b).ih $(b).h $(b).obj $(b).dll -del $(b).map $(b).sym $(b).res $(b).def ═══ 3.3.2. Representing the Styler Object ═══ Use the icon editor to create an icon that is suitable for representing the Styler object on the Desktop and save it as WPSTYLER.ICO. The following figure shows a sample icon for the Styler object: Now you are set to build and register your object with the Workplace Shell. ═══ 4. Debugging Workplace Shell Applications ═══ Debugging a Workplace Shell application is somewhat like debugging a Presentation Manager application. But because Workplace Shell objects are implemented via DLLs instead of EXEs, they can be more of a challenge. This chapter describes the SOM and Workplace Shell facilities and techniques to aid debugging applications. ═══ 4.1. About SOM Debugging Techniques ═══ Normally when an application is not working correctly, adding temporary printf statements or WinMessageBox calls can provide additional debugging information. SOM provides somPrintf that writes debugging information to the current stdout device. This is usually not convenient for Workplace Shell applications, because they are implemented in DLLs. To redirect the debugging output to another location, SOM provides a replaceable procedure called SOMOutCharRoutine. In addition to handling calls from somPrintf, the SOMOutCharRoutine is also invoked by the MethodDebug calls in every method. By replacing this procedure, output can be redirected from stdout to a more suitable location. When debugging is complete, the user-defined procedure can be removed or commented-out. Debugging information can be written to any number of places: o To stderr o To a window o To the clipboard o To a log file o Or any combination of the above. ═══ 4.2. About Workplace Shell Debugging Techniques ═══ The Workplace process is the one under which all the Workplace Shell classes are loaded and initialized. Therefore, objects representing Workplace Shell classes and their subclasses must run on this process. The Workplace process is actually launched from the Shell process, which is the process indicated in the SET PROTSHELL= statement in the CONFIG.SYS file. Once the Shell process is running, it starts the Workplace process. It is the Shell process that is responsible for restarting the Workplace process in the event that it is killed as a result of a trap. The PROTSHELL= statement in the CONFIG.SYS file indicates which process is to be launched as the Shell process. The SET RUNWORKPLACE= statement in the CONFIG.SYS file indicates which process is to be the Workplace process. In the default configuration, both the PROTSHELL and RUNWORKPLACE environment variables are set to PMSHELL.EXE. PMSHELL.EXE is designed to distinguish between being started as the Shell process versus being started as the Workplace process. ═══ 4.3. Using SOM Debugging Techniques ═══ This section describes two SOM techniques to aid debugging Workplace Shell applications: o One writes the information to a file o The other writes the information out through a serial port to an attached computer or dumb terminal. ═══ 4.3.1. Redirecting SOMOutCharRoutine to a File ═══ The following sample code shows how to direct somPrintf output to a file called C:\ERROR.TXT. Before enabling the replacement of SOMOutCharRoutine, the file is opened and a header is written to it. #define INCL_DOS #define INCL_WINWORKPLACE #include #include #include #include #include #include #include /* File to contain debugging error information */ static FILE *ErrorFile; /**********************************************************************/ /* This is the replacement for the default SOMOutCharRoutine. */ /* It writes the debugging information to a file on the hard drive */ /* instead of to stdout. */ /**********************************************************************/ #pragma linkage(myCharacterOutputRoutine, system) int SOMLINK myCharacterOutputRoutine(char chOut) { fputc((int) chOut, ErrorFile); fflush(ErrorFile); return 1; /* Indicate success */ } . . . /**********************************************************************/ /* Enable myCharacterOutputRoutine by opening the output error */ /* file and then changing the output character routine. */ /**********************************************************************/ ErrorFile = fopen ("c:\\error.txt", "a"); fprintf (ErrorFile, "\nDebug information from my WPS Object\n"); fprintf (ErrorFile, "------------------------------------\n"); setbuf (ErrorFile, NULL); SOM_TraceLevel = 2; /* Request maximum debugging information */ SOM_WarnLevel = 2; SOM_AssertLevel = 2; /* All output goes to my routine after the next statement */ SOMOutCharRoutine = myCharacterOutputRoutine; ═══ 4.3.2. Redirecting SOMOutCharRoutine to a Serial Port ═══ Instead of directing the output to a file, the SOMOutCharRoutine procedure can be used to direct the output to a serial port. By connecting another computer or a dumb terminal to the serial port with a NULL modem cable, debugging information can be received on the remote terminal. A NULL modem cable is a specialized serial cable that has the transmit and receive wires crossed so that transmissions from one serial port are received by another. First, initialize the serial port using the OS/2 Mode command. This command can be added to the STARTUP.CMD file or entered from an OS/2 command prompt. The following example shows how to use the Mode command: MODE COM1 9600,n,8,1 Replace SOMOutCharRoutine with your procedure which directs somPrintf output to the COM1 serial port as shown in the following sample code: #define INCL_DOS #define INCL_WINWORKPLACE #include #include #include #include #include #include #include /* COM1 port for debugging information */ static FILE *DebugPort; /**********************************************************************/ /* This is the replacement for the default SOMOutCharRoutine. */ /* It writes the debugging information to the COM1 serial port */ /* instead of to stdout. */ /**********************************************************************/ #pragma linkage(myCharacterOutputRoutine, system) int SOMLINK myCharacterOutputRoutine(char chOut) { fputc((int) chOut, DebugPort); fflush(DebugPort); return 1; /* Indicate success */ } . . . /**********************************************************************/ /* Enable myCharacterOutputRoutine by opening the serial port */ /* and then changing the output character routine. */ /**********************************************************************/ DebugPort = fopen("COM1", "w"); fprintf(DebugPort, "\nDebug information from my WPS Object\n"); fprintf(DebugPort, "------------------------------------\n"); setbuf(DebugPort, NULL); SOM_TraceLevel = 2; /* Request maximum debugging information */ SOM_WarnLevel = 2; SOM_AssertLevel = 2; /* All output goes to my routine after the next statement */ SOMOutCharRoutine = myCharacterOutputRoutine; ═══ 4.4. Using Workplace Shell Debugging Techniques ═══ This section describes how to use the PROTSHELL and RUNWORKPLACE variables to setup a development environment. It also provides two techniques to aid debugging Workplace Shell applications: o Lower level debugger, the Kernel Debugger o Source level debugger, IPMD ═══ 4.4.1. Debugging with Useful CONFIG.SYS Statements ═══ The PROTSHELL= statement specifies the name of the program for the Shell process of the Workplace Shell. The default is PMSHELL.EXE. This program loads the Workplace process and handles restarting it, should it fail. The SET RUNWORKPLACE= statement specifies the name of the program for the Workplace process of the Workplace Shell. The default is also PMSHELL.EXE. PMSHELL recognizes whether it should act as the Shell process or as the Workplace process. Setting this to be CMD.EXE will cause an OS/2 command prompt to be started instead of the Workplace Shell process. The SET SHELLEXCEPTIONHANDLER=OFF statement disables the Workplace Shell trap handler. The default is ON, which can mask problems with a Workplace Shell application. The SET RESTARTOBJECTS=NO statement prevents objects from being re-opened or re-started when the Workplace Shell is initialized. This is useful when there is an object that is causing a problem in the Workplace Shell. ═══ 4.4.2. Starting and Restarting the Workplace Shell ═══ The Workplace Shell starts automatically when OS/2 is booted. Because all Workplace Shell applications run under the Workplace process, one application with an error can cause the Workplace Shell to trap or to hang. Should the Workplace Shell become inoperative, the system must be rebooted. To avoid frequent reboots, one method that can be used is to start the Workplace Shell from an OS/2 window. Then should a hang occur, the Workplace Shell can be terminated by going to the OS/2 window and entering a Ctrl+Break. The procedure for manually starting and restarting the Workplace Shell is as follows: 1. Create a backup copy of your CONFIG.SYS file, for example: COPY CONFIG.SYS CONFIG.WPS 2. Edit CONFIG.SYS. Find the following line: SET RUNWORKPLACE=C:\OS2\PMSHELL.EXE where C: is your boot drive. This line sets the name of the interface to be started for OS/2. PMSHELL.EXE is the program for the Workplace Shell. Replace the line with the following: SET RUNWORKPLACE=C:\OS2\CMD.EXE This changes the OS/2 interface from the Workplace Shell to an OS/2 session. 3. By default, the Workplace Shell attempts to recover from any traps caused by itself or other Workplace Shell applications. Should this recovery occur, you might see all the objects on the Desktop disappear temporarily and then re-appear after the Workplace Shell re-initializes. The Workplace Shell exception handler can be disabled by adding the following line to the CONFIG.SYS file: SET SHELLEXCEPTIONHANDLER=OFF With the exception handler disabled, errors will result in the typical OS/2 error pop-up windows. Thus, errors encountered will not be masked by the Workplace Shell's exception handler. However, the ability for the Workplace Shell to recover from errors has been impacted. 4. Save the changes to CONFIG.SYS. These changes will not take effect until a shutdown and reboot are performed. 5. Shutdown the system and then reboot. 6. After the system reboots, instead of bringing up the Workplace Shell (PMSHELL.EXE), the system will bring up an OS/2 prompt (CMD.EXE). 7. Start another OS/2 session by issuing START or START /FS for a full-screen session. This session can be used for running other programs if needed. 8. Return to the original OS/2 session, and then manually start the Workplace Shell by typing: PMSHELL It is important to invoke PMSHELL from the first OS/2 session. There are two reasons for this: o First, the Workplace Shell assumes that it is the first process in the system. o Secondly, OS/2 assumes that the first application to create a message queue is the Workplace Shell and allocates additional resources for it. If another application creates a message queue before the Workplace Shell, unpredictable problems occur when the Workplace Shell is started. Now that the Workplace Shell has been started from an OS/2 session, should the Workplace Shell trap or hang, it can be stopped by simply going back to that OS/2 session and terminating the session, for example, by selecting the Ctrl+Break keys. The Workplace Shell can then be restarted from the same window by invoking PMSHELL again. After the Workplace Shell has terminated, the DLLs containing Workplace Shell objects should be unlocked. This allows them to be deleted or replaced before restarting the Workplace Shell. ═══ 4.4.3. Debugging with the Kernel Debugger ═══ The Kernel debugger included with the OS/2 Toolkit is a low-level debugger oriented toward system and device-driver debugging. The kernel debugger can assist in debugging Workplace Shell applications until higher-level debuggers, such as IPMD, can provide adequate debugging functions in complex situations. When the Kernel debugger is installed, two files are copied to the root directory of the boot drive: OS2KRNL and OS2KRNL.SYM. OS2KRNL is a hidden file, which will be renamed OS2KRNL.RTL when debugging is active. Because the Kernel debugger supports symbolic debugging, numerous symbol files (.SYM files) are copied to the \OS2\DEBUG\DLL directory. These symbol files contain information on symbols defined and used by OS/2. To make symbols defined in your Workplace Shell application available to the Kernel debugger, use the MAPSYM program. MAPSYM converts the .MAP file generated by the linker to a .SYM file. The .SYM file should reside in the same directory as the .EXE or .DLL executable file it represents and it should have the same name. When using the Kernel debugger, it is a good idea to use the functionprefix= modifier in the IDL file implementation statement. There are three reasons for this: o All the methods in the class start with the same prefix o The methods are not static o It is easier to locate the appropriate methods in the debugger and to set breakpoints. In the following sample code, the methods generated are called Dogdisplay and Dogbark. /****************************************************************/ /* By adding the functionprefix= modifier to the class, all */ /* methods defined will be unique, for example, Dogbark. */ /* This is useful when debugging, because every method in the */ /* class will start with this prefix and will not be static. */ /****************************************************************/ #ifndef dogdbug_idl #define dogdbug_idl #include interface Dog : SOMObject { attribute string breed; // The breed for the dog void display(); // Display characteristics for this dog void bark(); // Have the dog bark #ifdef __SOMIDL__ implementation { releaseorder: _get_breed, _set_breed, display, bark; //# Class modifiers functionprefix = Dog; // This will help when debugging callstyle = oidl; majorversion = 1; minorversion = 2; }; #endif /* __SOMIDL__ */ }; #endif As soon as the Kernel debugger is active, use the .p command to display process information. The Process ID (pid) of the Shell process and the Workplace process can be located quickly using this command. The following figure shows an example of the information you obtain when using the .p command: ## .p Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name 0001 0001 0000 0000 0001 blk 0100 ffe3a000 ffe3c7d4 ffe3c620 1e7c 00 *ager 0002 0001 0000 0000 0002 blk 0200 7b92a000 ffe3c7d4 7bb28020 1f3c 00 *tsd 0003 0001 0000 0000 0003 blk 0200 7b92c000 ffe3c7d4 7bb281d4 1f50 00 *ctxh 0004 0001 0000 0000 0004 blk 081f 7b92e000 ffe3c7d4 7bb28388 1f48 00 *kdb 0005 0001 0000 0000 0005 blk 0800 7b930000 ffe3c7d4 7bb2853c 1f20 00 *lazyw 0006 0001 0000 0000 0006 blk 0800 7b932000 ffe3c7d4 7bb286f0 1f3c 00 *asyncr 0008 0005 0001 0005 0001 blk 0200 7b936000 7bb458a4 7bb28a58 00 cmd *0009# 0006 0005 0006 0001+--------------------------+7bb28c0c 1eb8 01 pmshell 000d 0006 0005 0006 0002| |7bb292dc 01 pmshell 000e 0006 0005 0006 0003| In this example, |7bb29490 01 pmshell 000f 0006 0005 0006 0004| Pid #6 is the first |7bb29644 01 pmshell 0010 0006 0005 0006 0005| PMSHELL process, or |7bb297f8 01 pmshell 0007 0006 0005 0006 0006| the "Shell process". |7bb288a4 1ecc 01 pmshell 0013 0006 0005 0006 0007| |7bb29d14 01 pmshell 0015 0006 0005 0006 0008+--------------------------+7bb2a07c 01 pmshell 0016 0006 0005 0006 0009 blk 0200 7b952000 7bb44020 7bb2a230 01 pmshell 0017 0006 0005 0006 000a blk 0800 7b954000 7bb44020 7bb2a3e4 01 pmshell 0018 0006 0005 0006 000b blk 0800 7b956000 7bb44020 7bb2a598 01 pmshell 0019 0006 0005 0006 000c blk 0800 7b958000 7bb44020 7bb2a74c 01 pmshell 001a 0006 0005 0006 000d blk 0804 7b95a000 7bb44020 7bb2a900 01 pmshell 001b 0006 0005 0006 000e blk 0804 7b95c000 7bb44020 7bb2aab4 01 pmshell 001c 0006 0005 0006 000f blk 0500 7b95e000 7bb44020 7bb2ac68 01 pmshell 001d 0006 0005 0006 0010 blk 0800 7b960000 7bb44020 7bb2ae1c 1bb0 01 pmshell Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name 001e 0006 0005 0006 0011 blk 0800 7b962000 7bb44020 7bb2afd0 1b8c 01 pmshell 001f 0006 0005 0006 0012 blk 0200 7b964000 7bb44020 7bb2b184 01 pmshell 000a 0003 0000 0003 0001 blk 0200 7b93a000 7bb4484c 7bb28dc0 00 lanmsgex 000b 0004 0000 0004 0001 blk 0200 7b93c000 7bb45078 7bb28f74 00 lsdaemon 000c 0007 0006 0007 0001 blk 0800 7b93e000 7bb460d0 7bb29128 00 harderr 0011 0007 0006 0007 0002 blk 0800 7b948000 7bb460d0 7bb299ac 00 harderr 0012 0007 0006 0007 0003 blk 0800 7b94a000 7bb460d0 7bb29b60 00 harderr 0014 0008 0000 0008 0001 blk 0200 7b94e000 7bb468fc 7bb29ec8 01 stoplan 0020 0009 0006 0009 0001 blk 0500 7b966000 7bb47128 7bb2b338 1eb8 10 pmshell 0021 0009 0006 0009 0002 blk 0200 7b968000 7bb47128 7bb2b4ec 10 pmshell 0022 0009 0006 0009 0003+--------------------------+7bb2b6a0 1eb8 10 pmshell 0023 0009 0006 0009 0004| |7bb2b854 1ecc 10 pmshell 0024 0009 0006 0009 0005| In this example, |7bb2ba08 10 pmshell 0025 0009 0006 0009 0006| Pid #9 is the second |7bb2bbbc 10 pmshell 0026 0009 0006 0009 0007| PMSHELL process, or |7bb2bd70 10 pmshell 0027 0009 0006 0009 0008| the "Workplace |7bb2bf24 10 pmshell 0028 0009 0006 0009 0009| process". |7bb2c0d8 10 pmshell 002a 0009 0006 0009 000b| |7bb2c440 1eac 10 pmshell 002b 0009 0006 0009 000c+--------------------------+7bb2c5f4 1eb8 10 pmshell 0029 000a 0006 000a 0001 blk 0200 7b978000 7bb47954 7bb2c28c 11 cmd 002c 000b 0006 000b 0001 blk 0200 7b97e000 7bb48180 7bb2c7a8 12 cmd 002f 001f 0006 001f 0001 blk 0200 7b984000 7bb4a230 7bb2ccc4 15 cmd Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name 0030 001d 0006 001d 0001 blk 0200 7b986000 7bb49a04 7bb2ce78 13 cmd ## The Kernel debug command VSF * sets the trap vectors. This allows traps in the Workplace Shell application to be located quickly. The Kernel debugger stops on the instruction that is about to cause a trap when these vectors are set. In this way, it is possible to examine the stack and registers to determine the cause of the trap. ═══ 4.4.4. Debugging with IPMD ═══ The Starting and Restarting the Workplace Shell technique can also be used when a source level debugger is needed. Follow the same steps as outlined in that section, but instead of simply invoking PMSHELL, invoke the debugger, as follows: IPMD PMSHELL The debugger initializes, but the Workplace Shell does not start running. The steps to be followed are: 1. Select the Startup option from the File pull-down menu, as shown in the following figure: 2. Select the Debug program initialization option, as shown in the following figure: 3. Select the Load Occurence option from the Breakpoints pull-down menu, as shown in the following figure: 4. Enter a breakpoint by specifying the name (but not the path) of the DLL, for example, DOG.DLL. Then, select the Set push button, as shown in the following figure: 5. Set any other breakpoints you wish at this time. Select the OK push button when finished. 6. Select the Run option from the Breakpoints pull-down menu, as shown in the following figure: The Workplace Shell will then initialize (very slowly) and the debugger will stop when one of the specified breakpoints is reached. Debugging a Workplace Shell application using IPMD will be much the same as debugging a PM application. Remember that if you manually enter the name of a class or instance variable into IPMD, you must prefix the name with somThis instead of using the underscore ( _ ) macro. In the sample code fragment illustrated in the following figure, to manipulate the _hIcon variable in IPMD, use somThishIcon instead of _hIcon (selecting _hIcon with the mouse works as expected). /****************************************************/ /* Method: wpclsInitData */ /* */ /* This sample shows how to initialize class data */ / * associated with MyDataBase. */ /****************************************************/ SOM_Scope void SOMLINK MyDataBaseM_wpclsInitData(M_MyDataBase *somSelf) { /* M_MyDataBaseData *somThis = M_MyDataBaseGetData(somSelf); */ M_MyDataBaseMethodDebug("M_MyDataBase","MyDataBaseM_wpclsInitData"); hModule = _clsQueryModuleHandle(somSelf); _hIcon = WinLoadPointer(HWND_DESKTOP, hModule, ID_WINDOW); parent_wpclsInitData(somSelf); } ═══ 5. Object Aid: Help Methods ═══ This chapter describes how to write Workplace Shell applications that provide help information. ═══ 5.1. About Help Methods ═══ While running an application or viewing a document, the user may require help on the application or document. For example, an application may be a descendant of WPFolder class, to which you added a new context menu. You then need to provide a help dialog for this new context menu. It is important to include the help information for all applications as it is used often. This chapter describes different methods that can be overridden in order to provide help from an application window when a user requests it either by: o Pressing the F1 key o Selecting a Help push button o Selecting an item from a Help submenu. ═══ 5.1.1. Query and Set Object-Specific Help ═══ To query and set object-specific help for an instance of the object override wpQueryDefaultHelp and wpSetDefaultHelp. The wpQueryDefaultHelp method queries the default help panel ID and help library for this instance of the object class, as shown in the following figure: It automatically returns the class default help, if no object-specific help has been provided. wpQueryDefaultHelp (WPObject *somSelf, PULONG pHelpPanelId, PSZ HelpLibrary) where pHelpPanelId - Pointer to the help panel ID HelpLibrary - Help library name returned in the buffer The wpSetDefaultHelp method sets the default help panel ID and help library for this instance of the object class, as shown in the following figure: It allows different instances to have different helps displayed. Using the value zero for HelpPanelId and NULL for HelpLibrary, will reset the object to the default class help panel. wpSetDefaultHelp (WPObject *somSelf, ULONG HelpPanelId, PSZ HelpLibrary) where HelpPanelId - Help panel identity HelpLibrary - Help library name returned in the buffer ═══ 5.1.2. Setup Strings ═══ An object's default help panel ID and help library can be set using setup strings. The pszSetupString contains a series of keynames in which each is separated by semicolons, and which changes the behavior of the object. The following table shows the keynames used to set the default help panel ID and help library: ┌──────────────────────────────┬──────────────────────────────┐ │Keyname │Description │ ├──────────────────────────────┼──────────────────────────────┤ │HELPPANEL = id │Sets the object's default help│ │ │panel. This is equivalent to │ │ │calling wpSetDefaultHelp. │ ├──────────────────────────────┼──────────────────────────────┤ │HELPLIBRARY = myobject.hlp │Sets the default help library │ │ │for the object's instance. │ │ │This is equivalent to calling │ │ │wpSetDefaultHelp. │ └──────────────────────────────┴──────────────────────────────┘ The following methods can be called to set the object's default help panel ID and help library using setup strings: o wpSetup(WPObject *self, PSZ pszSetupString) o WinCreateObject(PSZ pszClassName, PSZ pszTitle, PSZ pszSetupString, PSZ pszLocation, ULONG ulFlags) o WinSetObjectData(HOBJECT hObject, PSZ pszSetupString) ═══ 5.1.3. REXX Functions ═══ The following REXX functions can be called to set the help panel ID and help library: o SysCreateObject(classname, title, location, setup, Flag) o SysSetObjectData(objectid, setup). ═══ 5.2. Using Help Methods ═══ This section explains, through the use of sample code fragments, how to: o Display the Help dialog for a pop-up menu item o Modify the Help dialog for a pop-up menu item o Query when a user requests help from an application window. ═══ 5.2.1. Displaying the Help Dialog for a Pop-Up Menu Item ═══ To display the Help dialog for a pop-up menu item, override wpMenuItemHelpSelected. Derived classes can override this method to: o Add the Help dialog for a new pop-up menu item o Modify the Help dialog for an existing menu item. The three following sample codes show how to override wpMenuItemHelpSelected. They present the class interface definition (IDL), source code (C), and Information Presentation Facility (IPF) files, respectively. passthru: C.ih; . . #define IDM_CLOSEVIEWS (WPMENUID_USER+1) #define ID_HELP_CLOSEVIEWS 257 . . endpassthru; //# Method modifiers . . wpMenuItemHelpSelected: override; . . The following sample code shows the source code for MYOBJECT when using wpMenuItemHelpSelected: /* * METHOD: wpMenuItemHelpSelected * * DESCRIPTION: * * Process the help submenu item that was added. */ SOM_Scope BOOL SOMLINK myobj_wpMenuItemHelpSelected(MYOBJECT *somSelf, ULONG MenuId) { MYOBJECTData *somThis = MYOBJECTGetData(somSelf); MYOBJECTMethodDebug("MYOBJECT","myobj_wpMenuItemHelpSelected"); switch(MenuId) { case IDM_CLOSEVIEWS: /* Append the new help library onto the system library, by calling * wpDisplayHelp(WPObject *self, ULONG HelpPanelId, PSZ HelpLibrary). * wpDisplayhelp sends a message to the help manager to display the help * panel. ID_HELP_CLOSEVIEWS should have the same value as the resid in * the Information Presentation Facilty (MYOBJECT.IPF), that is, in this * particular case, ID_HELP_CLOSEVIEWS is defined as 257 and the resid * for the context menu help item in MYOBJECT.IPF is also 257. */ return(_wpDisplayHelp(somSelf,ID_HELP_CLOSEVIEWS,szHelpLibrary)); break; default: break; } /* Always return the parent's method in case of default */ return (parent_wpMenuItemHelpSelected(somSelf,MenuId)); } The following sample code illustrates the OS/2 Information Presentation Facility (IPF) for the class MYOBJECT: .*===============================================================*\ .* * .* myobject.ipf - Information Tag Language file for the MYOBJECT * .* Class sample application's help manager * .* * .*===============================================================*/ :userdoc. .*---------------------------------------------------------------*\ .* Default Help for MYOBJECT class * .* res = ID_HELP_DEFAULT * .*---------------------------------------------------------------*/ :h1 res=256 name=ID_HELP_DEFAULT.MYOBJECT Class -- Help :i1 id=aboutMain.About MYOBJECT Class :p.This Class is a subclass of WPObject. .*---------------------------------------------------------------*\ .* Context Menu Item help * .* res = ID_HELP_CLOSEVIEWS * .*---------------------------------------------------------------*/ :h1 res=257 name=ID_HELP_CLOSEVIEWS.Close Views Menu Item :i1 id=IV.CloseViews :p.When this context menu item is chosen, all currently open views of this folder will be closed, except for the view that was initially opened. If no views are currently open, then no action will be taken. :euserdoc. ═══ 5.2.2. Requesting Help from an Application Window ═══ When a user requests help from an application window by pressing the F1 key, the wpclsQueryDefaultHelp method should be overridden, as shown in the following figure: wpclsQueryDefaultHelp(M_MYOBJECT *somSelf, PULONG pHelpPanelId, PSZ HelpLibrary) where pHelpPanelId - Pointer to the help panel ID HelpLibrary - Help library name returned in the buffer This method is called to allow the class object to specify its default help panel for its instances. This class method is called during the default processing of wpQueryDefaultHelp. It can be called at any time in order to determine the default help panel for the object class. The WPObject class does not process this method other than returning FALSE. Derived classes can override this method to provide the default help panel ID and help module name for their object instances. All classes should override this method to tell the system what help they want displayed when the user selects the F1 key. In this case, also, the value of ID_HELP_DEFAULT should be the same as the resid for the default help for MYOBJECT class in the IPF file. The three following sample codes show how to override wpclsQueryDefaultHelp. They present the class interface definition (IDL), source code (C), and make (MAK) files, respectively. passthru: C.ih; . . #define ID_HELP_DEFAULT 256 . . endpassthru; //# Class modifiers . . wpclsQueryDefaultHelp: override; . . The following sample code shows the source code of MYOBJECT when overriding wpclsQueryDefaultHelp: /* * METHOD: wpclsQueryDefaultHelp * * DESCRIPTION: * * Process input from the help submenu item that was added. */ SOM_Scope BOOL SOMLINK myobjM_wpclsQueryDefaultHelp(M_MYOBJECT *somSelf, PULONG pHelpPanelId, PSZ pszHelpLibrary) { /* M_MYOBJECTData *somThis = M_MYOBJECTGetData(somSelf); */ M_MYOBJECTMethodDebug("M_MYOBJECT","myobjM_wpclsQueryDefaultHelp"); if (pHelpPanelId) /* Set the default help panel ID */ *pHelpPanelId = ID_HELP_DEFAULT; if (pszHelpLibrary) /* Copy the help file name */ strcpy(pszHelpLibrary, szHelpLibrary); return (TRUE); } The help library can be created by using the IPFC compiler. The following figure shows the make file of MYOBJECT: myobject.hlp: $$(@B).ipf ipfc $*.ipf ═══ 6. Object Containers: Container Methods ═══ A container is a visual component that holds objects. CUA container control is the primary way of interacting with Workplace Shell objects. All objects with which the user interacts are simply records that have been inserted into a container control. Any Workplace Shell object can be inserted into any container control created on the Workplace process. This chapter describes the different views available for containers, and the methods used to create and manipulate containers in Workplace Shell applications. ═══ 6.1. About Container Methods ═══ A container can display objects in various formats and views. Generally speaking, each view displays different information about each object. If a container's data is too large for the window's work area, scrolling mechanisms are enabled. Containers are an integral component of the CUA user interface. ═══ 6.1.1. Container Views ═══ A Container view lists the components of an object. The components can be ordered or unordered in the view; the order of the information displayed in a contents view does not affect the meaning of the object containing the information. CUA guidelines describe three kinds of Container views: o Icon view An Icon view displays each object as an icon. Its purpose is to give the user an easy way to change the position of objects or to otherwise directly manipulate them. An object usually is represented by only one icon. However, for some tasks, the user might find it convenient to represent an object with more than one icon. For example, the user might want a representation of a printer object in more than one place so that the user can have easy access to the printer from anywhere. The user can create an additional icon, known as a shadow, to represent the same printer object. The following figure shows an Icon view with objects: o Tree view The Tree view displays container objects arranged hierarchically. The leftmost objects displayed in the Tree view are at the root level and are the same objects displayed in all the other Container views. Objects that contain other objects are called parent objects. The objects that a parent object contains are called child objects and can be displayed only in the Tree view. Child objects that contain other objects serve a dual role: they are the children of their parent object, but they are parent objects as well, with children of their own. For example, a parent object might be a book that contains individual child objects for its chapters or a folder that contains several reports. The chapters or reports, in turn, could be parent objects that contain their own children, such as the major sections of a chapter or report. If the child objects of a parent object are not displayed, the parent object can be Expanded to display them as a new branch in the Tree view. Once a parent item has been expanded, it can be Collapsed to remove its child objects from the display. The following figure shows a Tree view with objects: o Details view A Details view combines small icons with text that provides additional information about objects. The type of information displayed depends on the type of object and the type of tasks the user wants to perform. A Details view gives the user access to some of the object's more frequently used information, without requiring the user to open the object. Small icons are included in a Details view to provide a way for the user to easily recognize objects and to directly manipulate each object. Some Workplace Shell classes define a set of information that a user can display in a Details view of all instances of objects belonging to the class. The following figure shows a Details view with objects: ═══ 6.1.2. Container Objects ═══ A container object holds other objects. Its primary purpose is to provide a way for the user to group related objects for easy access and retrieval. To illustrate its importance, consider the example of the design of a software model of a car dealership. A salesperson needs a car object to represent each car model on his lot. He also needs a customer object to represent each customer who purchases a car. He needs a worksheet object to track sales, profits, inventory, customers, and so on. Finally, he needs a container objects to group these objects. The following figure shows a container holding several related objects: ═══ 6.2. Using Container Methods ═══ This section provides an example of what the Workplace Shell covers versus the container control. Secondly, it explains why the Workplace Shell subclasses the owner of a container and the frame window. Finally, this section describes the Workplace Shell container methods. More specifically, it explains how to: o Insert one object into a container o Insert multiple objects into a container o Remove an object from a container o Set emphasis on an object o Register a new open view o Obtain the object's MINIRECORDCORE pointer o Obtain a pointer to an object ═══ 6.2.1. Workplace Shell and the Container Control ═══ CUA container control is the primary key of interacting with Workplace Shell objects. All objects with which the user interacts are simply records that have been inserted into a container control. The container control uses RECORDCORE and MINIRECORDCORE structures to represent the items that it holds. Memory for these structures is allocated by sending the container a CM_ALLOCRECORD message. When memory is allocated, the records may be inserted using the CM_INSERTRECORD message. The Workplace Shell provides object instance methods that perform all of this for you. When an object is created, the Workplace Shell automatically allocates memory for the MINIRECORDCORE structure and stores the pointer in the object's instance data. Only one MINIRECORDCORE per object is used even if the object exists in multiple views. The wpQueryCoreRecord method can be used to obtain the pointer to the MINIRECORDCORE structure that was allocated when the object was created. You would use this method to obtain a pointer to the MINIRECORDCORE structure that the container is using to represent the object. This may be necessary if you need to perform a task and no instance method for that task exists. If the container can perform the task, the application can use _wpQueryCoreRecord to obtain the PMINIRECORDCORE and send the container a message explicitly. The OBJECT_FROM_PREC macro performs the inverse function of _wpQueryCoreRecord and is used to obtain a pointer to the object (self) when the pointer to the MINIRECORDCORE structure is known. ═══ 6.2.2. Workplace Shell Container Owner Subclass Procedure ═══ Any Workplace Shell object can be inserted into any container control created on the Workplace process using wpCnrInsertObject. When an object is inserted into a container via _wpCnrInsertObject, the Workplace Shell subclasses the owner of the container, and intercept some messages and notifications from the container. In this way, the Workplace Shell provides support that maps container records to their WPObject counterparts, and related behaviors. In other words, using the object's instance methods to insert an object into a container allows the object to inherit all of the Workplace Shell features, such as context menu, and Pickup and Drop operation. Note: Since the Workplace Shell subclasses the container control's owner, you can only have ONE container control into which you are inserting objects per owner. This means you may have to expand your window hierarchy. When a view is registered, the Workplace Shell subclasses the frame window. The Workplace Shell adds the viewed object's context menu to the system menu of the view. The Workplace Shell assumes that the container window has an ID of FID_CLIENT and that the container's owner is a frame window. This means that the container window is the client area of a frame window that was created with WinCreateStdWindow. When a view of an object is opened, a USAGE_OPENVIEW item is added to the object's in-use list. The USAGE_OPENVIEW items are used to automatically switch to the open view when the user chooses to open the same view again. This behavior is controlled by wpOpen or wpSwitchTo. For more detail on the USAGE_OPENVIEW item, see Object Usage: Usage Methods. ═══ 6.2.3. Inserting Container Objects ═══ The wpCnrInsertObject and wpclsInsertMultipleObjects methods are used to insert objects into a container window. Objects inserted using these methods automatically inherit the default Workplace Shell behavior such as context menus, and Pickup and Drop capability. When an object is inserted into a container, the Workplace Shell will add a USAGE_RECORD item to the object's in-use list. There will be one of these USAGE_RECORD items for each view (container window) that the object is inserted in. These methods send the CM_INSERTRECORD message to the container window. ═══ 6.2.3.1. Inserting One Object ═══ The wpCnrInsertObject method inserts a record into a container control window. The following shows the syntax of wpCnrInsertObject: #define INCL_WINWORKPLACE #include PMINIRECORDCORE wpCnrInsertObject (WPObject *self, HWND hwndCnr, PPOINTL pIcon, PMINIRECORDCORE pParent, PRECORDINSERT pRecInsert) The self (WPObject *) parameter is the pointer to the object on which the method is being invoked. It points to an object of class WPObject. The hwndCnr (HWND) parameter is the handle of the container control window. The pIcon (PPOINTL) parameter is the pointer to a POINTL structure specifying the initial icon position in the container control window. The pParent (PMINIRECORDCORE) parameter is the pointer to the parent record. The pParent parameter specifies the record of the immediate parent of the record being inserted. This parameter should be set to NULL, if the record has no parent or if the Tree view is not supported. The pRecInsert (PRECORDINSERT) parameter is the pointer to the RECORDINSERT structure specifying how this record is to be inserted relative to other records in the same container. The possible values of this parameter are: Value Description NULL Insert the record into the next available position. Other Insert the record into the position specified by pRecInsert. The rc (PMINIRECORDCORE) parameter is returned with one of the following values: Value Description NULL Error occurred. Other Pointer to the inserted record. This method is used to give Workplace Shell object behavior (such as context menu support) to records inserted directly into a WC_CONTAINER control window. To remove records from the container, a call to wpCnrRemoveObject should be made. The following figure shows the insertion of an object into a container control window: /************************************************************************/ /* This sample code assumes that the object has already been created */ /* using wpclsNew and object's pointer has been obtained */ /* using wpclsQueryObject. */ /************************************************************************/ WPObject *self; /* The object to be inserted */ HWND hwndCnr; /* Handle of the container */ /* window */ POINTL ptlIcon; /* Location within container */ /* to place record */ RECORDINSERT RecordInsert; /* Container RECORDINSERT */ /* data structure */ /************************************************************************/ /* Set up the RECORDINSERT data structure. */ /* The object will be inserted at the beginning of the list of records. */ /************************************************************************/ RecordInsert.cb = sizeof(RECORDINSERT); /* Size of the RECORDINSERT */ /* data structure */ RecordInsert.pRecordParent = NULL; /* Insert record at root */ /* level */ RecordInsert.zOrder = CMA_TOP; /* Top of the z-order */ RecordInsert.cRecordsInsert = 1; /* Inserting 1 record */ RecordInsert.fInvalidateRecord = TRUE; /* Invalidate record at the */ /* time it is inserted */ RecordInsert.pRecordOrder = /* Place record at beginning */ (PRECORDCORE)CMA_FIRST; /* of the list of records */ /* already inserted */ /************************************************************************/ /* Initialize the location where the object will be inserted. */ /************************************************************************/ ptlIcon.x = 50; ptlIcon.y = 50; /************************************************************************/ /* Inserting object at location 50,50. */ /************************************************************************/ _wpCnrInsertObject(self, hwndCnr, &ptlIcon, NULL, &RecordInsert) ═══ 6.2.3.2. Inserting Multiple Objects ═══ The wpclsInsertMultipleObjects method is used to insert multiple objects into a container window at one time. The following shows the syntax of wpclsInsertMultipleObjects: #define INCL_WINWORKPLACE #include BOOL wpclsInsertMultipleObjects(M_WPObject *self, HWND hwndCnr, PPOINTL pptlIcon, PVOID *pObjectArray, PVOID pRecordParent, ULONG NumRecords) The self (M_WPObject *) parameter is the pointer to the WPObject class object. The hwndCnr (HWND) parameter is the handle of the container window to insert objects into. The pptlIcon (PPOINTL) parameter is the pointer to a POINTL structure specifying the coordinates for the position of the first object inserted. The pObjectArray (PVOID *) parameter is the pointer to an array of object pointers. The objects in this array are to be inserted into the container. The pRecordParent (PVOID) parameter is the parent record pointer. This parameter should be set to NULL if the records being inserted will not have a parent or if the Tree view is not supported. The NumRecords (ULONG) parameter is the number of objects in the pObjectArray parameter. The rc (BOOL) parameter is returned with one of the following values: Boolean Description TRUE Objects successfully inserted into the container. FALSE Error occurred. This method is used for the rapid insertion of multiple objects into the container all at once. The wpCnrInsertObject method performs the same function as this method but operates on only one object at a time. This method will add each of the objects to the in-use list. The following figure shows the insertion of multiple objects into a container control window: BOOL wpclsInsertMultipleObjects(M_WPObject *self, HWND hwndCnr, PPOINTL pptlIcon, PVOID *pObjectArray, PVOID pRecordParent, ULONG NumRecords) M_WPObject *self; HWND hwndCnr; POINTL ptlIcon; PVOID pObjectArray{5}; ULONG i; /************************************************************************/ /* pObjectArray has been filled in with pointers to objects */ /* created using WinCreateObject or wpClsNew */ /************************************************************************/ /************************************************************************/ /* Initial location for first object being inserted. */ /************************************************************************/ ptlIcon.x = 50; ptlIcon.y = 50; /************************************************************************/ /* Inserting multiple objects. */ /************************************************************************/ _wpclsInsertMultipleObjects(self, hwndCnr, &ptlIcon, &pObjectArray, NULL,5); ═══ 6.2.4. Removing Container Objects ═══ The wpCnrRemoveObject method should be called to remove an object from a container, if that object was inserted using either wpCnrInsertObject or wpclsInsertMultipleObjects. When the object is removed from a container, the USAGE_RECORD item, which was added to the in-use list when the object was inserted, will be removed. This method sends the CM_REMOVERECORD message to the container. The following shows the syntax of wpCnrRemoveObject: #define INCL_WINWORKPLACE #include BOOL wpCnrRemoveObject (WPObject *self, HWND hwndCnr, PMINIRECORDCORE pRecord) The self (WPObject *) parameter is the pointer to the object on which the method is being invoked. It points to an object of class WPObject. The hwndCnr (HWND) parameter is the handle of the container control window. The pRecord (PMINIRECORDCORE) parameter is the pointer to the record to be removed. rc (BOOL) is returned with one of the following values: Boolean Description TRUE Record successfully removed. FALSE Error occurred. The following figure shows the deletion of an object from a container control window: /************************************************************************/ /* This sample code assumes that the object has already been */ /* created using wpclsNew and object's point has been */ /* obtained using wpclsQueryObject. */ /************************************************************************/ WPObject *self; /* The object to be removed */ HWND hwndCnr; /* Handle of the container window */ PMINIRECORDCORE pRecord; /* Pointer to container record */ /************************************************************************/ /* Removing the record from the container window. */ /************************************************************************/ _wpCnrRemoveObject(self, hwndCnr, pRecord); ═══ 6.2.5. Setting Emphasis on Objects ═══ The wpCnrSetEmphasis method provides a way to change the visual emphasis of an object. Visual emphasis can be used to give the user feedback as to the state of the object. For example, when a folder is opened on the Desktop, in-use emphasis is added to the folder icon. The Workplace Shell accomplishes this by calling wpCnrSetEmphasis on the object. This method sends the CM_SETRECORDEMPHASIS message to the container. The CRA_* flags that are specified for the ulEmphasisAttr parameter are the same as those for the CM_SETRECORDEMPHASIS container message. The following shows the syntax of wpCnrSetEmphasis: #define INCL_WINWORKPLACE #include BOOL wpCnrSetEmphasis (WPObject *self, ULONG ulEmphasisAttr, BOOL fTurnOn) The self (WPObject *) parameter is the pointer to the object on which the method is being invoked. It points to an object of class WPObject. The ulEmphasisAttr (ULONG) parameter is the type of emphasis to set on the object. The CRA_* flags are as follows. These flags are the container's record attribute flags. The flags may be combined using the logical OR ( | ) operator. Emphasis Type Description CRA_CURSORED Specifies that the record will be drawn with a selection cursor. CRA_DISABLED Specifies that the record will be drawn with unavailable-state emphasis. CRA_INUSE Specifies that a record will be drawn with in-use emphasis. CRA_PICKED Specifies that the record will be drawn with "picked" emphasis. It is part of the Pickup and Drop operation. CRA_SELECTED Specifies that a record will be drawn with selected-state emphasis. CRA_SOURCE Specifies that the record will be drawn with source-menu emphasis. The fTurnOn (BOOL) parameter sets or resets the specified attribute. Boolean Description TRUE Set the specified attribute. FALSE Reset the specified attribute. rc (BOOL) is returned with one of the following values: Boolean Description TRUE Attribute successfully set. FALSE Error occurred. The following figure shows how to set the emphasis on a container object: /************************************************************************/ /* This sample code assumes that the object has already been created */ /* using wpclsNew and object's pointer has been obtained */ /* using wpclsQueryObject. */ /************************************************************************/ WPObject *self; /* The object whose emphasis is being set */ ULONG ulEmphasis; /* ULONG data structure */ ulEmphasis = CRA_INUSE; /* Emphasis type desired */ /************************************************************************/ /* Setting emphasis on the object. */ /************************************************************************/ _wpCnrSetEmphasis(self, ulEmphasis, TRUE); ═══ 6.2.6. Registering a New Open View ═══ The wpRegisterView method should be called whenever a new view of an object is created. Registering a view will set the title of the frame window to the object's title and add the view title as the current view in the window list. The wpRegisterView method is used to allow an object to register a new open view. The following shows the syntax of wpRegisterView: #define INCL_WINWORKPLACE #include BOOL wpRegisterView (WPObject *self, HWND hwndFrame, PSZ pszViewTitle) The self (WPObject *) parameter is the pointer to the object on which the method is being invoked. It points to an object of class WPObject. The hwndFrame (HWND) parameter is the handle of the frame window containing the new view. The pszViewTitle (PSZ) parameter is the pointer to a string containing the name of the view. The rc (BOOL) parameter is returned with one of the following values: Boolean Description TRUE New view successfully registered. FALSE Error occurred. Registering a view will set the object title as the title of the frame window and add a view title as the current view in the window list and titlebar. The following figure shows how to register a new open view of an object: WPObject *self; HWND hwndFrame; PSZ pszViewTitle="OS/2 Programs - Icon View"; _wpRegisterView(self, hwndFrame, pszViewTitle); ═══ 6.2.7. Obtaining the Object's MINIRECORDCORE Pointer ═══ The wpQueryCoreRecord method is used to obtain a pointer to the MINIRECORDCORE structure associated with a given object. When an object is created, the Workplace Shell automatically allocates memory for a MINIRECORDCORE structure and stores a pointer to it in the object's instance data. The following shows the syntax of wpQueryCoreRecord: #define INCL_WINWORKPLACE #include PMINIRECORDCORE wpQueryCoreRecord (WPObject *self); The self (WPObject *) paramter is the pointer to the object on which the method is being invoked. It points to an object of class WPObject. The pRecord (PMINIRECORDCORE) parameter is returned. It points to the MINIRECORDCORE structure for the object. Every object has a MINIRECORDCORE structure associated with it so it can be placed into a container. This method is used to obtain the PMINIRECORDCORE when the pointer to the object is known. The following figure shows how to obtain a pointer to the MINIRECORDCORE structure associated with an object: PMINIRECORDCORE pRecord; WPObject *self; pRecord = _wpQueryCoreRecord(self); ═══ 6.2.7.1. Obtaining a Pointer to an Object ═══ The OBJECT_FROM_PREC macro is used to obtain a pointer to an object when the PMINIRECORDCORE is known. The following figure shows how to obtain a pointer to an object: WPObject *self; PMINIRECORDCORE pRecord; self = OBJECT_FROM_PREC(pRecord); ═══ 7. Object Criteria: Details Methods ═══ The class defines the object's instance data and methods. Details data are part of instance data and define more accurately the behavior of the object. This chapter describes the general concepts of Details data and explains how to use the details methods in Workplace Shell applications. ═══ 7.1. About Details Methods ═══ The basic unit of organization of SOM programs is the object. SOM objects consist of instance data and methods. SOM classes define the behavior of sets of like objects. You can think of a SOM class as a description of an object. The class defines the object's instance data and methods. Details data are part of instance data and define more accurately the behavior of the object. Not all classes have the Details data section defined. Only those classes that have a requirement to store such information define this section as part of the instance data. After the Details data are defined, it is the class creator's responsibility to set and use them correctly. Details data allows you to: o Define, for a class of objects, some confidential data along with general data o Have a special container Details view o Choose specific Details fields to be displayed in Details view by filtering out unwanted fields o Filter objects that match or do not match a set of criteria o Search for objects based on a single or complex set of criteria o Sort objects. The Details data of all objects contained in a container can be displayed in a Details view. The fields that are displayed in the Details view correspond to the Object type (class object) that is selected in the View page (page three of the View pages) of the Settings notebook. Once the Object type selected, the fields are listed in the Details to display drop-down list box. the following figure shows an example of the Details view for a Workplace Shell class. Each record provides information for a specific instance of an object belonging to the class. Details for Instances of MyObject Class ┌───────┬─────────┬──────────────┬┬────────┬────────┬────────┐ │ Icon │ Title │ Object Class ││ Field1 │ Field2 │ Field3 │ ├───────┼─────────┼──────────────┤├────────┼────────┼────────┤ Instance 1 │ │ │ ││ │ │ │ ├───────┼─────────┼──────────────┤├────────┼────────┼────────┤ Instance 2 │ │ │ ││ │ │ │ ├───────┼─────────┼──────────────┤├────────┼────────┼────────┤ │ │ │ ││ │ │ │ │ │ │ ││ │ │ │ └───────┴─────────┴──────────────┴┴────────┴────────┴────────┘ This Details view window is two windows separated by a split bar. The left side of the window contains, at least, the Title column (the default column) and can also contain the Details fields available for all classes and, in turn, for all objects. The right side of the window can be empty, if the objects to be represented are not descended from the chosen class. The user can choose: o Which class provides Details fields to the window o Which Details fields of this class are visible. By default, the system sets the WPFileSystem class that provides all Details fields to be visible. The Workplace Shell provides a Settings notebook, page three of the View pages, to set the class and Details fields to be displayed in the Details view. The following figure shows the Settings notebook, page three of the View pages: A record that contains information for an object instance of the class is created by overriding wpQueryDetailsData. The column headings for a Details view are specified by overriding wpclsQueryDetailsInfo. An object can inherit the set of Details data defined by its ancestors. A record containing Details data for an object can also contain sets of Details data from objects that are defined by its parent or ancestors. The Workplace Shell handles this by creating records of contiguous blocks of memory. To inherit the details defined by ancestor classes, wpQueryDetailsData calls the parent class wpQueryDetailsData, which calls its parent class wpQueryDetailsData, and so forth, until the oldest ancestor that defined Details data is reached. In addition to inheriting Details data from its ancestors, the object can have some of its own. For each call to wpQueryDetailsData, a variable-length block of memory containing a set of Details data for the object is added to the record. A pointer is moved to the end of the last block of memory added to the record, where the next call to wpQueryDetailsData adds the next block of memory. Each block in the record contains a set of Details data for the object defined by its class or by one of its ancestor classes, as shown in the following figure: ───────┬─────────────────┬─────────────────┬─────────────────┬────── │ Details Defined │ Details Defined │ Details Defined │ │ by MyObject's │ by MyObject's │ by MyObject │ │ Ancestor │ Parent │ │ ───────┴─────────────────┴─────────────────┴─────────────────┴────── The format for Details data contained in a record is defined by overriding wpclsQueryDetailsInfo. The format is defined in a linked list of CLASSFIELDINFO data structures for each Details field in a record. This linked list is created the same way as a record: wpclsQueryDetailsInfo calls its parent class wpclsQueryDetailsInfo, which calls its parent class wpclsQueryDetailsInfo, and so forth. Each call adds a set of CLASSFIELDINFO data structures to the linked list until the list contains all CLASSFIELDINFO data structures for each Details field of the object's Details record, as shown in the following figure: Format of Format of Format of Details Data Details Data Details Data Defined by Defined by Defined by its Ancestor its Parent MyObject ┌────────────┐ ┌────────────┐ ┌────────────────────────────┐ ──>Field1─>Field2────>Field3─>Field4────>Field5─>Field6─>Field7─>Field8───> The CLASSFIELDINFO data structure describes the attributes of Details data for each field. ═══ 7.2. Using Details Methods ═══ The CAR sample Workplace Shell object in the Toolkit can be used to illustrate the requirements for defining Details data for a class of objects. CAR can provide Details data for CAR objects by: 1. Defining a data structure for the Details fields to be included in the Details view, as shown in the following sample code: /* CARDETAILS: Structure used for Details view */ typedef struct _CARDETAILS { PSZ pszMake; /* Manufacturer */ PSZ pszModel; /* Model */ PSZ pszColor; /* Color of car */ CDATE cdateSale; /* Date of sale */ ULONG ulPrice; /* Price in dollars */ } CARDETAILS; typedef CARDETAILS *PCARDETAILS; 2. Defining and initializing a static array of CLASSFIELDINFO structures for each set of Details data, as shown in the following sample code. This is done on class initialization, when wpclsInitData is called. Note: Title and Icon details are defined for CAR objects by its ancestor class WPObject. This means that the CLASSFIELDINFO data structures for Title and Icon details are defined and initialized in the WPObject class definition. #define NUM_CAR_FIELDS 5 CLASSFIELDINFO fieldinfo[NUM_CAR_FIELDS]; PSZ pszCarColTitles[] = { "Make", /* Details column 1 */ "Model", /* Details column 2 */ "Color", /* Details column 3 */ "Sale date", /* Details column 4 */ "Price ($)" /* Details column 5 */ }; . . . /****************************************************************/ /* Method: wpclsInitData */ /* Purpose: Initialize the Details data */ /****************************************************************/ SOM_Scope void SOMLINK carM_wpclsInitData(M_Car *somSelf) { USHORT rc, i; PCLASSFIELDINFO pCFI; /* M_CarData *somThis = M_CarGetData(somSelf); */ M_CarMethodDebug("M_Car","carM_wpclsInitData"); /* Call the parent class method first */ parent_wpclsInitData(somSelf); /* Get the class title */ if (!WinLoadString(WinQueryAnchorBlock(HWND_DESKTOP), _clsQueryModuleHandle(somSelf), ID_TITLE, sizeof(szCarClassTitle), szCarClassTitle)) /* If the load string has failed, use the parent's string */ strcpy(szCarClassTitle, parent_wpclsQueryTitle(somSelf)); /* Initialize everything needed for the CLASSFIELDINFO */ /* data structure for the CAR object class */ for (i=0,pCFI=fieldinfo;icb = sizeof(CLASSFIELDINFO); pCFI->flData = CFA_RIGHT | CFA_SEPARATOR | CFA_FIREADONLY; pCFI->flTitle = CFA_CENTER | CFA_SEPARATOR | CFA_HORZSEPARATOR | CFA_STRING | CFA_FITITLEREADONLY; pCFI->pNextFieldInfo = pCFI + 1; /* Point to the next CLASSFIELDINFO */ pCFI->pTitleData = (PVOID) apszCarColTitles[i]; pCFI->flCompare = COMPARE_SUPPORTED | SORTBY_SUPPORTED; switch (i) { case INDEX_MAKE: pCFI->flData |= CFA_STRING; pCFI->offFieldData = (ULONG)(FIELDOFFSET(CARDETAILS,pszMake)); pCFI->ulLenFieldData = sizeof(PSZ); pCFI->DefaultComparison = CMP_EQUAL; break; case INDEX_MODEL: pCFI->flData |= CFA_STRING; pCFI->offFieldData = (ULONG)(FIELDOFFSET(CARDETAILS,pszModel)); pCFI->ulLenFieldData = sizeof(PSZ); pCFI->DefaultComparison = CMP_EQUAL; break; case INDEX_COLOR: pCFI->flData |= CFA_STRING; pCFI->offFieldData = (ULONG)(FIELDOFFSET(CARDETAILS,pszColor)); pCFI->ulLenFieldData = sizeof(PSZ); pCFI->DefaultComparison = CMP_EQUAL; break; case INDEX_SALE_DATE: pCFI->flData |= CFA_DATE; pCFI->offFieldData = (ULONG)(FIELDOFFSET(CARDETAILS,cdateSale)); pCFI->ulLenFieldData = sizeof(CDATE); pCFI->ulLenCompareValue = sizeof(CDATE); pCFI->DefaultComparison = CMP_GREATER; break; case INDEX_PRICE: pCFI->flData |= CFA_ULONG; pCFI->offFieldData = (ULONG)(FIELDOFFSET(CARDETAILS,ulPrice)); pCFI->ulLenFieldData = sizeof(ULONG); pCFI->ulLenCompareValue = sizeof(ULONG); pCFI->DefaultComparison = CMP_GREATER; break; } /* End switch(i) */ } /* End for (i=0,pCFI=fieldinfo;ipNextFieldInfo) ? pCFI->pNextFieldInfo : pCFI; pCFI->pNextFieldInfo = fieldinfo; } else *ppClassFieldInfo = fieldinfo; } return ((ULONG) (cParentColumns + NUM_CAR_FIELDS)); } /* End carM_wpclsQueryDetailsInfo() */ 4. Adding Details data to an object's Details record by overriding wpQueryDetailsData, as shown in the following sample code: /* * Returns the car specific data for the Details view of this object. * Sets the pointer (*ppDetailsData) to the beginning of the buffer * into which the data is written. */ SOM_Scope ULONG SOMLINK car_wpQueryDetailsData(Car *somSelf, PVOID *ppDetailsData, PULONG pcp) { PCARDETAILS pCarDetails; PBYTE pSize; CarData *somThis = CarGetData(somSelf); CarMethodDebug("Car","car_wpQueryDetailsData"); parent_wpQueryDetailsData(somSelf,ppDetailsData,pcp); if (ppDetailsData) /* Query data */ { pCarDetails = (PCARDETAILS) *ppDetailsData; pCarDetails->pszMake = "Toyota"; /* Manufacturer */ pCarDetails->pszModel = "Camry"; /* Model name */ pCarDetails->pszColor = "BLUE"; /* Color of the car */ pCarDetails->cdateSale.day = 24; /* Date of sale */ pCarDetails->cdateSale.month = 12; pCarDetails->cdateSale.year = 91; pCarDetails->ulPrice = 14000; /* Price in dollars */ /* Point to buffer location after the Details data */ *ppDetailsData = ((PBYTE) (*ppDetailsData)) + sizeof(*pCarDetails); } /* End if (ppDetailsData) */ else /* Query size of data */ { /* Caller is querying the buffer size */ *pcp += sizeof(*pCarDetails); } return(TRUE); } /* End car_wpQueryDetailsData() */ ═══ 7.2.1. Including Objects in a Container ═══ A container represents the standard mode to organize objects you work with. It simply stores objects and allows them to interact with the user. Sometimes, however, a container can contain unnecessary objects. For this reason, the Workplace Shell provides a powerful tool that allows you to filter objects you want to include in or to exclude from the container. You specify objects to be included in a container by selecting the Include tab of the Settings notebook. The filter for this container is specified by the criteria that tells the system to include, in the container, all objects that match the criteria. The default criteria is shown in the following figure: I Flags less than --H- This criteria means that all objects that do not have the hidden attribute set will be included in the Open view of the container. The following figure shows the Include dialog, which is set with the default criteria: The Include dialog provides the following push buttons to manipulate criteria: Push Button Description Add Brings up a dialog for adding new criteria. Change Brings up a dialog for changing the selected criteria. Delete Deletes the selected criteria. Undo Resets the criteria to the state it was in when you opened the Include tab. Default Resets the criteria to the default criteria as shown in the second previous figure. Help Provides help on the Include tab. As an example, to set the criteria to include nothing (exclude everything), delete the default criteria and add the criteria shown in the following figure: E ObjectClass is equal to Object ═══ 7.2.1.1. Adding Criteria ═══ All objects in the system have properties such as name, date of creation, size, color, and so forth. A group of like objects make up a class. The objects in one class differ from the objects in another class by their properties. If a class is descended from another class, however, the objects from the descended class have, at least, all the properties of its parent, and can have some of their own. The following figure shows the Add Criteria dialog: To create a valid criteria, four elements must be specified: Element Description Attribute Lists all the different attributes you can select for the criteria. Comparison type Lists all the different comparison types associated with the selected attribute. Comparison value Lists all the different values associated with the selected attribute. Use of criteria Contains two radio buttons: o To include objects that match the criteria. o To exclude objects that match the criteria. The following table shows the attributes that are available in the system at installation time. The attributes are listed in the same order as the ones shown in the Attribute drop-down list box. ┌──────────────────────────────┬──────────────────────────────┐ │Attribute │Class │ ├──────────────────────────────┼──────────────────────────────┤ │ObjectTitle │WPObject │ ├──────────────────────────────┼──────────────────────────────┤ │ObjectStyle │WPObject │ ├──────────────────────────────┼──────────────────────────────┤ │ObjectClass │WPObject │ ├──────────────────────────────┼──────────────────────────────┤ │RealName │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Size │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │LastWriteDate │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │LastWriteTime │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │LastAccessDate │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │LastAccesTime │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │CreationDate │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │CreationTime │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Flags │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │ReadOnlyFlag │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │HiddenFlag │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │SystemFlag │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │DirectoryFlag │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │ArchivedFlag │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Subject │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Comments │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Key Phases │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │History │WPFileSystem │ ├──────────────────────────────┼──────────────────────────────┤ │Extended Attribute Size │WPFileSystem │ └──────────────────────────────┴──────────────────────────────┘ After selecting the attribute, comparison type, and comparison value, select the appropriate radio button to specify whether to include or exclude objects that match the specified criteria. ═══ 7.2.1.2. Changing Criteria ═══ The following figure shows the Change Criteria dialog: To change a criteria, specify the Attribute, Comparison type, Comparison value, or Use of criteria, and select the Change push button. ═══ 7.2.2. Searching for Objects ═══ The Workplace Shell has a Find tool that allows you to search for objects based on several criteria. Every container pop-up menu in the system has a Find Objects dialog. The following figure shows the Find Objects dialog: You use the Find Objects dialog to search for objects by their names, or by selecting the More push button and by specifying several criteria. The Find Objects dialog comes with default values: Default Values Description Name Specifies the name of the object to search for. The asterisk (*) is the default and means to search for all object names. Start Folder Specifies where the search begins. The default is the path of the container from which the Find process is started. For the Desktop, the default is . The drop-down list box contains additional options, including the specific drives available in the system. Search All Subfolders Specifies to search all subfolders. The default is to search the specified folder. Save Results Creates a folder containing the Find result objects. The Find result objects are shadows of the objects, not the objects themselves. If this option is not checked, Find creates a window with icons that represent pointers to the real objects. This is the default option. Locate Allows you to specify another starting point for the Find process. The following figure shows the Locate dialog. The focus is on the Desktop tab. The Locate dialog contains five options: Option Description Desktop Lists all folders in the Desktop folder. Drives Displays the contents of a drive in Tree view. Opened Lists all folders currently open on the Desktop. Path Specifies, in command line format, where the search begins. This is an alternative to Start Folder. Related Gives the Tree view for the drive from which the Find process started. More Specifies more criterias for the Find process. This brings up the same dialog window as the one used in "Changing Criteria". Find Starts the search process. After the Find process is started, a Search in progress dialog is displayed. When the search is completed a Find results window comes up that shows the name of all objects found. ═══ 7.2.3. Sorting Objects ═══ You specify objects to sort on by selecting the Sort tab of the Settings notebook. The following figure shows the Sort dialog: There are four elements to consider for sorting objects: Element Description Object type Defines the type of object to sort on. Sort by attribute Defines the attributes to sort on. The attributes are associated with the object type selected. Default sort attribute Specifies the system default sort attribute. Always maintain sort order Refreshes any Open views every time a folder's object is moved, copied, or shadowed inside or outside its folder. To select the previous sort criteria, press the Undo push button. To select the default sort criteria, press the Default push button. Two object Details fields introduced by WPObject are sortable criteria: Name and Type. WPFileSystem introduces eight other sortable criteria. The following table shows the name of each detail as shown on the object's context menu: ┌───────────────────────┬───────────────────┐ │Object Details Field │Attribute │ ├───────────────────────┼───────────────────┤ │Name │Name │ ├───────────────────────┼───────────────────┤ │Type │Type │ ├───────────────────────┼───────────────────┤ │Real name │Real name │ ├───────────────────────┼───────────────────┤ │Size of the file │Size │ ├───────────────────────┼───────────────────┤ │Last modification date │Last write date │ ├───────────────────────┼───────────────────┤ │Last modification time │Last write time │ ├───────────────────────┼───────────────────┤ │Last access date │Last access date │ ├───────────────────────┼───────────────────┤ │Last access time │Last access time │ ├───────────────────────┼───────────────────┤ │Date of creation │Creation date │ ├───────────────────────┼───────────────────┤ │Time of creation │Creation time │ └───────────────────────┴───────────────────┘ WPObject and WPFileSystem are the only system classes that contribute Details fields to the Sort dialog of the Settings notebook. User-defined class may introduce their own Details fields as sort criteria. The sort class for a particular container determines what class' sort Details fields will appear as active sort criteria on the container's Sort dialog of the Settings page. The default sort class for all containers is WPFileSystem. This sort class can be manually changed via the container's Settings page, and it can also be programmatically changed by using wpSetFldrSortClass. The wpSetFldrSortClass and wpQueryFldrSortClass methods are needed to set both the Always maintain sort order checkbox on a container's Sort dialog, as well as the chosen sort field. ═══ 8. Object Errors: Error Handling Methods ═══ The Workplace Shell provides methods which you can override to design your own error handling system, using error objects. This chapter provides information on error handling methods for Workplace Shell applications. ═══ 8.1. About Error Handling Methods ═══ The WPObject class provides methods which can be overridden to design your own error handling system. The wpQueryError method obtains the error identity that was set on an object by the last call to wpSetError. The wpQueryError method can be called at any time. The wpSetError method sets the error identity on an object. Typically, this method is called prior to returning from a method that is unsuccessful. The wpQueryError method is then called to identify the error. Similar to object errors, class errors can also be queried and set using wpclsQueryError and wpclsSetError. The wpclsQueryError method obtains the error identity that was set on a class object by the last call to wpclsSetError. The wpclsQueryError method can be called at any time. The wpclsSetError method sets the error identity on a class object. Typically, this method is called prior to returning from a class method that is unsuccessful. The wpclsQueryError method is then called to identify the error. ═══ 8.2. Using Error Handling Methods ═══ This section describes, via sample code fragments, how you can use the error handling methods. Specifically the first sample code shows how wpQueryError retrieves the error identity that was set on an object. The second code fragment shows how to design your own error handling system by overriding wpSetError. The following sample code shows how wpQueryError retrieves the error identity that was set on an object: // METHOD: my_wpDrop // // DESCRIPTION: // SOMObject // |__ WPObject // |__ WPFileSystem // |__ WPFolder // |__ MyFolder // // When an object is dropped on a folder, // this method is called on the target folder. // // This sample code shows how wpQueryError retrieves // the error identity that was set on an object. // SOM_Scope MRESULT SOMLINK my_wpDrop(MyFolder *self, HWND hwndCnr, PDRAGINFO pDragInfo, PDRAGITEM pDragItem) { MRESULT mr; // Return value ULONG ulError; // Error code set on folder // Clear existing error code _wpSetError(self, NO_ERROR); // Call the parent to handle the drop mr = parent_wpDrop(self, hwndCnr, pDragInfo, pDragItem); // If parent returns an error, check to see if the disk is full if (mr == (MRESULT)RC_DROP_ERROR) { // Query the error code set on the folder ulError = _wpQueryError(self); // If the disk is full, display a message to the user if (ulError == ERROR_DISK_FULL) { WinMessageBox(HWND_DESKTOP, NULLHANDLE, // Owner Window "Error Disk Full", // Body of the message "Unsuccessful Drop", // Title of the message 0, // Message box id MB_ERROR | MB_OK); // Icon and button flags } } return mr; } The following sample code shows shows how to design your own error handling system by overriding wpSetError: // METHOD: my_wpSetError // // DESCRIPTION: // Sets the error on an object. // User-defined errors can be handled here. // // This sample code shows how to design your own // error handling system by overriding wpSetError. SOM_Scope BOOL SOMLINK my_wpSetError(MyFolder *self, ULONG ulErrorId) { // Check to see if this is a user-defined error if (ulErrorId > WPERR_USER) { // Handle user-defined errors here } // Call the parent to set the error return (parent_wpSetError(self, ulErrorId)); } ═══ 9. Object Information: Set/Query Methods ═══ The Workplace Shell provides several set and query methods that you can use to set or to get object information, such as the default view of the object's in-use list, the object's icon, and the object's title. This chapter provides information for using object information methods. It describes how to define the behavior of Workplace Shell objects, using applicable styles. ═══ 9.1. About Set/Query Methods ═══ The set and query methods are used to set and interrogate the properties of objects. The information associated with an object can be: o Default help o Default view o Error set o Handle o Icon o Icon data o Identifier o Settings page size o Title. As some methods relate to one another, they have been grouped into the following sections: o General (including Class style and Object style) o Data file o Desktop o Disk (File-System Device) o File System o Folder o Icon o Network o Palette o Power o Printer o Program reference and program file o Shadow o View. Each section is divided into tables that are grouped as follows: o Methods that obtain information and that are overridden o Methods that obtain information but are not normally overridden o Methods that set information and that are overridden o Methods that set information but are not normally overridden. Note: The help, error, and sort methods are explained in the following chapters: Error handling methods Object Errors: Error Handling Methods. Sort methods Object Criteria: Details Methods. Help methods Object Aid: Help Methods. ═══ 9.1.1. General Characteristics Methods ═══ A program or Workplace Shell object would call the following methods to get general information about an object. A Workplace Shell object would override these methods to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryConfirmations │Returns the set of │ │ │confirmations that are set for│ │ │this object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDefaultHelp │Returns the object's default │ │ │help panel. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryNameClashOption │Returns the set of options │ │ │that are not available on the │ │ │name clash dialog for this │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryStyle │Returns the object's style. │ │ │See Object Styles. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryTitle │Returns the object's title. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryDefaultHelp │Returns the class default help│ │ │panel. This help panel is used│ │ │for all objects of this class.│ │ │The default help panel can be │ │ │changed for an individual │ │ │object if: │ │ │ │ │ │o The object overrides │ │ │ wpQueryDefaultHelp. │ │ │o The wpSetDefaultHelp method │ │ │ is called. │ │ │o The wpSetup method is called│ │ │ with the HELPPANEL keyword. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQuerySetting │Returns a settings value for │ │ │an abstract class object. An │ │ │abstract class object would │ │ │override this method if it │ │ │saved its class settings. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryStyle │Returns the class style. See │ │ │Class Styles. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryTitle │Returns the class title. This │ │ │title is used for all objects │ │ │of this class, including the │ │ │class template. The title can │ │ │be changed for an individual │ │ │object if: │ │ │ │ │ │o The object overrides │ │ │ wpQueryTitle. │ │ │o The wpSetTitle method is │ │ │ called. │ │ │o The wpSetup method is │ │ │ called with the TITLE │ │ │ keyword, when the user │ │ │ edits the object's title │ │ │ on the General page of the │ │ │ Settings notebook, or when │ │ │ the user edits the │ │ │ object's title under │ │ │ the icon. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to get general information about an object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryContainerFlagPrt │Returns the pointer to a flag │ │ │indicating whether or not the │ │ │object is in a container. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryCoreRecord │Returns the pointer to the │ │ │object's MINIRECORDCORE data │ │ │structure. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDefaultIconPos │Returns the default icon │ │ │position used when this object│ │ │is first inserted into a │ │ │folder. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryError │Returns the last error code │ │ │set by calling the object's │ │ │wpSetError. This is normally │ │ │an error code being returned │ │ │by a failing instance method. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFolder │Returns the object pointer for│ │ │the folder containing the │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryHandle │Returns the object's unique │ │ │persistent handle. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryObjectID │Returns the object's │ │ │identifier. The object │ │ │identifier is set by calling │ │ │wpSetObjectID for the object │ │ │or by calling wpSetup for the │ │ │object with the OBJECTID │ │ │keyword. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryScreenGroupID │Returns the screen group │ │ │identifier of the application │ │ │running for this object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryStyle │Returns the object's current │ │ │style flags. See Object Styles│ │ │. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryError │Returns the last error code │ │ │set by calling the class' │ │ │wpclsSetError. This is │ │ │normally an error code that is│ │ │returned by a failing class │ │ │method. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryFolder │Returns the pointer to the │ │ │folder object that corresponds│ │ │to the specified file system │ │ │path. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryObject │Returns the pointer to the │ │ │object that corresponds to the│ │ │specified persistent object │ │ │handle. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryStyle │Returns the object class' │ │ │style. See Class Styles. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set general information about an object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpModifyStyle │Sets or clears individual │ │ │flags within the object's │ │ │style. This method call is an │ │ │atomic operation as only the │ │ │specified style flags are │ │ │changed, even if other running│ │ │threads try to modify the │ │ │style flags at the same time. │ │ │See Object Styles. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDefaultHelp │Sets the object's default help│ │ │panel. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDefaultIconPos │Sets the object's default icon│ │ │position which is used when it│ │ │is inserted into a folder. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetError │Sets the current error code │ │ │for the object. This method is│ │ │normally called by an instance│ │ │method to pass an error code │ │ │back to the caller. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetObjectID │Sets the object's identifier. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetStyle │Sets the object's style. This │ │ │method exists only for │ │ │compatibility with old │ │ │objects. All new or changed │ │ │objects should use │ │ │wpModifyStyle instead. See │ │ │Object Styles. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetTitle │Sets the object's title. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsSetError │Sets the current error code │ │ │for the class. This method is │ │ │normally called by a class │ │ │method to pass an error code │ │ │back to the caller. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to set general information about an object. A Workplace Shell object would override this method to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsSetSetting │Sets a settings value for an │ │ │abstract class object. An │ │ │abstract class object would │ │ │override this method if it │ │ │wants to save its class │ │ │settings. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.1.1. Class Styles ═══ Workplace Shell object classes have styles that define the behavior of all objects of that class. The object class style is defined by wpclsQueryStyle. When an object is created, the object's style is initially inherited from the class. The following table lists the class style flags: ┌──────────────────────────────┬──────────────────────────────┐ │Style Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERCOPY │Objects of this class cannot │ │ │be copied. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERDELETE │Objects of this class cannot │ │ │be deleted. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERDRAG │Objects of this class cannot │ │ │be dragged. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERLINK │Objects of this class cannot │ │ │have shadows. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERMOVE │Objects of this class cannot │ │ │be moved. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERPRINT │Objects of this class cannot │ │ │be printed. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERRENAME │Objects of this class cannot │ │ │be renamed. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERSETTINGS │Objects of this class cannot │ │ │be opened in Settings view. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERTEMPLATE │This class does not have a │ │ │template. Also, objects of │ │ │this class will not have a │ │ │Create another option in their│ │ │context menu. │ ├──────────────────────────────┼──────────────────────────────┤ │CLSSTYLE_NEVERVISIBLE │Objects of this class are │ │ │never visible. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.1.2. Object Styles ═══ Workplace Shell objects have styles that define their behavior. The object class style is defined by wpQueryStyle. When an object is created, the object's style is initially inherited from the class. The wpQueryStyle method can modify the style flags to tailor the object. Also, wpModifyStyle can be used to set or reset individual style flags for the object. The following table lists the object style flags: ┌──────────────────────────────┬──────────────────────────────┐ │Style Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOCOPY │The object cannot be copied. │ │ │The Copy option is not valid │ │ │for a direct manipulation │ │ │operation (Pickup and Drop) │ │ │and there is no Copy option in│ │ │the object's context menu. │ │ │This option is inherited from │ │ │the class' CLSSTYLE_NEVERCOPY │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NODELETE │The object cannot be deleted. │ │ │The object cannot be dragged │ │ │to the shredder and there is │ │ │no Delete option in the │ │ │object's context menu. This │ │ │option is inherited from the │ │ │class' CLSSTYLE_NEVERDELETE │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NODRAG │The object cannot be copied or│ │ │moved. Direct manipulation │ │ │operations (Pickup and Drop) │ │ │are not valid for this object │ │ │and there are no Copy, Move, │ │ │or Pickup options in the │ │ │object's context menu. This │ │ │option is inherited from the │ │ │class' CLSSTYLE_NEVERDRAG │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NODROPON │No other object can be dropped│ │ │on this object using a direct │ │ │manipulation operation (Pickup│ │ │and Drop). │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOLINK │The object cannot have │ │ │shadows. The Link option is │ │ │not valid for a direct │ │ │manipulation operation (Pickup│ │ │and Drop) and there is no │ │ │Create shadow option in the │ │ │object's context menu. This │ │ │option is inherited from the │ │ │class' CLSSTYLE_NEVERLINK │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOMOVE │The object cannot be moved. │ │ │The Move option is not valid │ │ │for a direct manipulation │ │ │operation (Pickup and Drop) │ │ │and there is no Move option in│ │ │the object's context menu. │ │ │This option is inherited from │ │ │the class' CLSSTYLE_NEVERMOVE │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOPRINT │The object cannot be printed. │ │ │The object cannot be dragged │ │ │to a Printer object and there │ │ │is no Print option in the │ │ │object's context menu. This │ │ │option is inherited from the │ │ │class' CLSSTYLE_NEVERPRINT │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NORENAME │This object cannot be renamed.│ │ │Its title cannot be changed │ │ │either by directly editing the│ │ │title under the icon or by │ │ │changing the title on the │ │ │General page of the Settings │ │ │notebook. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOSETTINGS │This object cannot be opened │ │ │in Settings view. There is no │ │ │Settings option in the │ │ │object's context menu. This │ │ │option is inherited from the │ │ │class' CLSSTYLE_NEVERSETTINGS │ │ │style. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_NOTDEFAULTICON │The icon associated with this │ │ │object is not the class │ │ │default icon. │ │ │ │ │ │Note: │ │ │You should never modify this │ │ │style option because the │ │ │Workplace Shell uses it for │ │ │the following reasons: │ │ │ │ │ │o When you copy an object, │ │ │ the Workplace Shell │ │ │ determines when to create │ │ │ a copy of the object's │ │ │ icon. │ │ │o When the Workplace Shell │ │ │ frees an icon. │ │ │ │ │ │If this style flag is set │ │ │incorrectly, the object's │ │ │icon could disappear or │ │ │could not be freed when │ │ │necessary, thereby wasting │ │ │system memory. │ ├──────────────────────────────┼──────────────────────────────┤ │OBJSTYLE_TEMPLATE │This object is a template. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.2. Data File Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a data file object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAssociatedFileIcon │Returns the handle of the icon│ │ │for the WPProgram or │ │ │WPProgramFile object │ │ │associated with the data file │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAssociatedProgram │Returns the pointer to the │ │ │WPProgram or WPProgramFile │ │ │object associated with the │ │ │data file object. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to set information about a data file object. This method may be overridden to force the association of a specific icon with a data file. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetAssociatedFileIcon │Change the icon associated │ │ │with the data file object. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.3. Desktop Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a Desktop object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpIsCurrentDesktop │Returns an indication of │ │ │whether or not the Desktop │ │ │object is the active Desktop. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryActiveDesktop │Returns the pointer to the │ │ │active Desktop object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryActiveDesktopHWND │Returns the window handle for │ │ │the active Desktop. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryObjectFromFrame │Returns the pointer to the │ │ │object associated with the │ │ │specified frame window. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.4. Disk (File-System Device) Related Methods ═══ A program or Workplace Shell object would call the following methods to set information about a disk object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDriveLockStatus │Returns the lock status of a │ │ │disk object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryLogicalDrive │Returns the logical drive │ │ │number for a disk object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryRootFolder │Returns the root folder object│ │ │for the logical drive │ │ │represented by a disk object. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to set information about a disk object. A disk object would override this method to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetCorrectDiskIcon │Sets the correct icon for the │ │ │disk object. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.5. File System Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a file system object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAttr │Returns the file attributes of│ │ │the file system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryCreation │Returns the creation date and │ │ │time of the file system │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDateInfo │Returns the file system │ │ │object's: │ │ │ │ │ │o Creation date and time │ │ │o Last access date and timeo │ │ │o Last update date and time. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDisk │Returns the pointer to the │ │ │disk object for the drive on │ │ │which the file system object │ │ │resides. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryEASize │Returns the size, in bytes, of│ │ │the extended attributes of the│ │ │file system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFilename │Returns the name of the file │ │ │system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFileSize │Returns the size, in bytes, of│ │ │the file system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryLastAccess │Returns the last access date │ │ │and time of the file system │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryLastWrite │Returns the last write date │ │ │and time of the file system │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryRealName │Returns the real name of the │ │ │file system object. For file │ │ │systems that do not support │ │ │long file names, such as the │ │ │FAT file system which allows 8│ │ │characters for the file name │ │ │and 3 for the extension, the │ │ │real name may be different │ │ │than the object's title. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryType │Returns the type of the file │ │ │system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryAwakeObject │Returns the pointer to the │ │ │file system object │ │ │corresponding to the specified│ │ │path name, if the file system │ │ │object is awake. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryInstanceFilter │Returns a string containing │ │ │the filter for files that │ │ │comprise the object class. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryInstanceType │Returns a string containing │ │ │the .TYPE attribute for the │ │ │files that comprise the object│ │ │class. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryObjectFromPath │Returns the pointer to an │ │ │object which represents the │ │ │given file or directory. │ └──────────────────────────────┴──────────────────────────────┘ i1.wpSetRealName A program or Workplace Shell object would call the following methods to set information about a file system object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetAttr │Changes the file attributes of│ │ │the file system object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDateInfo │Changes the file system │ │ │object's: │ │ │ │ │ │o Creation date and time │ │ │o Last access date and timeo │ │ │o Last update date and time. │ │ │ │ │ │Note: │ │ │This method changes only the │ │ │dates and times kept in the │ │ │persistent data of the file │ │ │system object. It does not │ │ │change the actual dates and │ │ │times kept by the underlying │ │ │file system. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFileSizeInfo │Changes the file size and │ │ │extended attribute size of the│ │ │file system object. │ │ │ │ │ │Note: │ │ │This method changes only │ │ │the sizes kept in the │ │ │persistent data of the file │ │ │system object. It does not │ │ │change the actual sizes used │ │ │by the underlying file │ │ │system. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetRealName │Changes the real name of the │ │ │file system object. This is │ │ │the name of the object │ │ │maintained by the underlying │ │ │file system. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetTitleAndRenameFile │Changes the file system │ │ │object's title and real name, │ │ │so that they match. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetType │Changes the .TYPE attribute of│ │ │the file system object. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.6. Folder Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a folder object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpIsDetailsColumnVisible │Returns the visibility state │ │ │of a specified Details view │ │ │column of the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpIsSortAttribAvailable │Returns an indication of │ │ │whether or not a sort │ │ │attribute is available for a │ │ │column of the Details view of │ │ │the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryContent │Returns the pointer to an │ │ │object contained in the │ │ │folder. This method may be │ │ │called within a loop to │ │ │enumerate all of the objects │ │ │contained in the folder. │ │ │ │ │ │Note: │ │ │The folder must be awake for │ │ │this method to return the │ │ │pointers to all objects │ │ │contained in the folder. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrAttr │Returns the folder object's │ │ │attributes. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrDetailsClass │Returns the class for which │ │ │data is displayed in the │ │ │Details view of the folder │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrFlags │Returns the current state of │ │ │the folder object's flags. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrFont │Returns the name of the font │ │ │used for the specified view of│ │ │the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrSort │Returns the sort attribute │ │ │used for the specified view of│ │ │the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryFldrSortClass │Returns the object class for │ │ │which sorting is performed for│ │ │the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryIconViewPos │Returns a pointer to the │ │ │IconViewPos array of the │ │ │folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryNextIconPos │Returns the next position at │ │ │which an icon is inserted into│ │ │the folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryOpenFolders │Returns the pointer to an open│ │ │folder object. This method may│ │ │be called in a loop to │ │ │enumerate all currently open │ │ │folders. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a folder object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpModifyFldrFlags │Sets or clears individual │ │ │flags within the folder │ │ │object. │ │ │ │ │ │Note: │ │ │This method is an atomic │ │ │operation as only the │ │ │specified flags are changed, │ │ │even if other running threads │ │ │try to modify the flags at │ │ │the same time. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDetailsColumnVisibility │Changes the visibility state │ │ │of a specified column of data │ │ │for the Details view of the │ │ │folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrAttr │Changes the folder object's │ │ │attributes. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrDetailsClass │Changes the object class for │ │ │which data is displayed in a │ │ │Details view of the folder │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrFlags │Changes the folder object's │ │ │flags. │ │ │ │ │ │Note: │ │ │This method exists only for │ │ │compatibility with old │ │ │objects. All new or changed │ │ │objects should use │ │ │wpModifyFldrFlags instead. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrFont │Changes the font used for the │ │ │specified view of the folder │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrSort │Changes the sort attribute for│ │ │the specified view of the │ │ │folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetFldrSortClass │Changes the object class for │ │ │which data is sorted for the │ │ │folder object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetNextIconPos │Changes the next position at │ │ │which an icon is inserted into│ │ │the folder object. This method│ │ │can be used to ensure that │ │ │objects inserted into the │ │ │folder are displayed where you│ │ │want them. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetSortAttributeAvailable │Changes the indication of │ │ │whether or not a sort │ │ │attribute is available for a │ │ │column of a Details view of │ │ │the folder object. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.7. Icon Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about an object's icons. A Workplace Shell object would override these methods to define its icons. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryIconData │Returns the information that │ │ │defines the object's icon. │ │ │This overrides the class │ │ │default icon defined by │ │ │wpclsQueryIconData. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryIconData │Returns the information that │ │ │defines the class default │ │ │icon. This icon is associated │ │ │with every object of this │ │ │class. This icon can be │ │ │changed for an individual │ │ │object if: │ │ │ │ │ │o The object overrides │ │ │ wpQueryIconData. │ │ │o The wpSetIconData method │ │ │ is called. │ │ │o The wpSetup method is called│ │ │ with the ICONFILE or │ │ │ ICONRESOURCE keyword, or if │ │ │ the user edits the icon on │ │ │ the General page of the │ │ │ Settings notebook. │ │ │ │ │ │For a folder class, this is │ │ │the closed folder icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryIconDataN │Returns the information that │ │ │defines the nth class default │ │ │animation icon. │ │ │ │ │ │Note: │ │ │This method is available only │ │ │for a folder class. It │ │ │defines the default open │ │ │folder icon for all objects │ │ │of this class. This icon can │ │ │be changed for an individual │ │ │object if wpSetup is called │ │ │with the ICONNFILE or │ │ │ICONNRESOURCE keyword, or if │ │ │the user edits the animation │ │ │icon on General page 2 of the │ │ │Settings notebook. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to get information about an object's icons. These methods are not normally overridden by the object. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryIcon │Returns the handle of the │ │ │object's icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryIcon │Returns the handle of the │ │ │class default icon. For a │ │ │folder class, this method │ │ │returns the handle of the │ │ │class' default closed folder │ │ │icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryIconN │Returns the handle of the nth │ │ │class default animation icon. │ │ │This method is available only │ │ │for a folder class. It returns│ │ │the handle of the class' │ │ │default open folder icon. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to change the icon for an object. These methods are not normally overridden by the object. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetIcon │Sets the handle of the │ │ │object's icon. This handle is │ │ │not saved in the persistent │ │ │data of the object, so it has │ │ │effect until the object goes │ │ │dormant. This method affects │ │ │all open views of the object. │ │ │For a folder object, wpSetIcon│ │ │affects the icon displayed: │ │ │ │ │ │o In the title bar. │ │ │o On the Launch Pad. │ │ │o On the General page 1 of │ │ │ the Settings notebook. │ │ │o In all containers if the │ │ │ object is closed. │ │ │ If the object is open, all │ │ │ containers continue to show │ │ │ the object's animation │ │ │ icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetIconData │Sets the definition for the │ │ │object's icon. This icon │ │ │definition is saved with the │ │ │persistent data of the object.│ │ │It permanently changes the │ │ │object's icon. This method │ │ │automatically calls wpSetIcon │ │ │to update the visual display │ │ │of the object's icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetProgIcon │Sets the visible icon │ │ │associated with the program │ │ │reference or program file │ │ │object. This method is │ │ │available only for a program │ │ │reference or program file │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsSetIcon │Sets the handle of the default│ │ │class icon. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsSetIconData │Sets the definition of the │ │ │default class icon. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.8. Network Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a network object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryNetIdentity │Returns the fully qualified │ │ │network name for a network │ │ │group object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryObjectNetId │Returns the network ID of the │ │ │shared directory object that │ │ │this object is linked to. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQuerySrvrIdentity │Returns the fully qualified │ │ │network name for this server │ │ │object. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a network object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetNetIdentity │Sets the fully qualified │ │ │network name for a network │ │ │group object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetObjectNetId │Sets the network ID of the │ │ │shared directory object that │ │ │this object is linked to. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.9. Palette Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a palette object. A palette object would override these methods to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPaletteHelp │Returns the help panel ID that│ │ │is displayed when the Help │ │ │push button is pressed in an │ │ │open palette view. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryEditString │Returns the title for the Edit│ │ │push button. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to get information about a palette object. This method is normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPaletteInfo │Returns information about the │ │ │palette. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to set information about a palette object. This method is normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetPaletteInfo │Changes the current │ │ │information about the palette.│ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.10. Power Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a power object. A power object would override these methods to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAutoRefresh │Returns the current state │ │ │(enabled or disabled) for │ │ │automatic refresh of the power│ │ │object's status window. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryRefreshRate │Returns the current refresh │ │ │rate (in minutes) for the │ │ │power object's status window │ │ │when automatic refresh is │ │ │enabled. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to get information about a power object. These methods are normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDefStatusView │Returns the default view for │ │ │the power object when │ │ │"Advanced power management" │ │ │(APM) is enabled. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPowerConfirmation │Returns the current state │ │ │(enabled or disabled) for the │ │ │power object's confirmation │ │ │message. This message is │ │ │optionally displayed when │ │ │power state changes are │ │ │requested from its context │ │ │menu. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPowerManagement │Returns the current state │ │ │(enabled or disabled) for │ │ │"Advanced power management" │ │ │(APM). │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a power object. These methods are normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetAutoRefresh │Enables or disables automatic │ │ │refresh of the power object's │ │ │status window. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDefStatusView │Sets the default status view │ │ │for the power object when │ │ │"Advanced power management" is│ │ │enabled. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetPowerConfirmation │Enables or disables the │ │ │display of the power object's │ │ │confirmation message when │ │ │power state changes are │ │ │requested from its context │ │ │menu. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetPowerManagement │Enables or disables "Advanced │ │ │power management". │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetRefreshRate │Sets the refresh rate for the │ │ │power object's status window │ │ │when automatic refresh is │ │ │enabled. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.11. Printer and Print Job Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a printer or print job object. These methods are normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryComputerName │Returns the name of the │ │ │computer on which the printer │ │ │object exists. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryJobFile │Returns the name of the spool │ │ │file for the print job object.│ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryJobId │Returns the job ID for the │ │ │print job object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryJobType │Returns the data type for the │ │ │print job object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryLocalAlias │Returns the name of the local │ │ │print queue for a remote │ │ │printer object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryNetworkId │Returns the fully qualified │ │ │network ID of the remote │ │ │printer queue for a remote │ │ │printer object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPrintername │Returns the name of the print │ │ │queue for this printer object.│ │ │For a remote printer object, │ │ │this is the computer's printer│ │ │queue name on which the │ │ │printer object exists. The │ │ │name of the local print queue │ │ │can be obtained by calling │ │ │wpQueryLocalAlias. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryPrintObject │Returns a pointer to the │ │ │printer object to which the │ │ │print job is associated with. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryQueueOptions │Returns the printer object's │ │ │queue options. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryRemoteOptions │Returns the printer object's │ │ │remote options. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a printer or print job object. These methods are normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetComputerName │Sets the name of the computer │ │ │on which the printer object │ │ │resides. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDefaultPrinter │Sets the printer object as the│ │ │default printer. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetPrinterName │Sets the name of the printer │ │ │object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetQueueOptions │Sets the printer object's │ │ │queue options. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetRemoteOptions │Sets the printer object's │ │ │remote options. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.12. Program Reference and Program File Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a program reference or a program file object. A program reference or program file object would override these methods to define its characteristics. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAssociationFilter │Returns the list of filters │ │ │that the program reference or │ │ │program file object is │ │ │associated to. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryAssociationType │Returns the list of types that│ │ │the program reference or │ │ │program file object is │ │ │associated to. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryProgramAssociations │Returns the list of filters or│ │ │types for the program │ │ │reference or program file │ │ │object. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following method to get information about a program reference or a program file object. This method is not normally overriden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryProgDetails │Returns the program details │ │ │for the program reference or │ │ │program file object. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a program reference or a program file object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetAssociationFilter │Changes the list of filters │ │ │that the program reference or │ │ │program file object is │ │ │associated to. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetAssociationType │Changes the list of types that│ │ │the program reference or │ │ │program file object is │ │ │associated to. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetProgDetails │Changes the program details │ │ │for the program reference or │ │ │program file object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetProgramAssociations │Changes the list of filters or│ │ │types that the program │ │ │reference or program file │ │ │object is associated to. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.13. Shadow Related Methods ═══ A program or Workplace Shell object would call the following method to get information about a shadow object. This method is normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryShadowedObject │Returns a pointer to the │ │ │object this shadow is linked │ │ │to. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set information about a shadow object. These methods are normally not overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetLinkToObject │Changes a shadow object to │ │ │link to a new object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetShadowTitle │Changes the title of a shadow │ │ │object without changing the │ │ │title of the object the shadow│ │ │is linked to. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.1.14. View Related Methods ═══ A program or Workplace Shell object would call the following methods to get information about a view of an object. A Workplace Shell object would override these methods to define the characteristics of its open views. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryButtonAppearance │Returns which button │ │ │(minimize, hide, or the system│ │ │default) appears in the frame │ │ │control for an open view of │ │ │the object. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryConcurrentView │Returns an indication of │ │ │whether or not this object │ │ │allows multiple concurrent │ │ │views to be opened. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryDefaultView │Returns the view of the object│ │ │that is opened when the │ │ │default view is opened. │ ├──────────────────────────────┼──────────────────────────────┤ │wpQueryMinWindow │Returns the behavior of the │ │ │object when it is minimized │ │ │(Minimize window to Desktop, │ │ │Minimize window to viewer, or │ │ │use the system default │ │ │behavior). │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryButtonAppearance │Returns the class default for │ │ │which button (minimize, hide, │ │ │or the system default) appears│ │ │in the frame control for an │ │ │open view of any object of │ │ │this class. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQueryDefaultView │Returns the class default of │ │ │which view of the object is │ │ │opened when the default view │ │ │is opened. The default view is│ │ │associated with every object │ │ │of the class. The default view│ │ │can be changed for an │ │ │individual object if: │ │ │ │ │ │o The object overrides │ │ │ wpQueryDefaultView. │ │ │o The wpSetDefaultView method │ │ │ is called. │ │ │o The wpSetup method is called│ │ │ with the DEFAULTVIEW │ │ │ keyword. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsQuerySettingsPageSize │Returns the size of the │ │ │Settings notebook pages │ │ │displayed for the object │ │ │class. │ └──────────────────────────────┴──────────────────────────────┘ A program or Workplace Shell object would call the following methods to set the characteristics for the open views of the object. These methods are not normally overridden. ┌──────────────────────────────┬──────────────────────────────┐ │Method Name │Description │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetButtonAppearance │Defines which button │ │ │(minimize, hide, or the system│ │ │default) appears in the frame │ │ │control for an open view of │ │ │the object. This value is │ │ │normally returned by │ │ │wpQueryButtonAppearance. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetConcurrentView │Defines whether or not the │ │ │object allows multiple │ │ │concurrent views to be opened.│ │ │This value is normally │ │ │returned by │ │ │wpQueryConcurrentView. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetDefaultView │Defines which view of the │ │ │object is opened when the │ │ │default view is opened. This │ │ │value is normally returned by │ │ │wpQueryDefaultView. │ ├──────────────────────────────┼──────────────────────────────┤ │wpSetMinWindow │Defines the behavior of the │ │ │object when it is minimized │ │ │(Minimize window to Desktop, │ │ │Minimize window to viewer, or │ │ │use the system default │ │ │behavior). This value is │ │ │normally returned by │ │ │wpQueryMinWindow. │ ├──────────────────────────────┼──────────────────────────────┤ │wpclsSetSettingsPageSize │Sets the size of the Settings │ │ │notebook pages displayed for │ │ │the object class. │ └──────────────────────────────┴──────────────────────────────┘ ═══ 9.2. Using Set/Query Methods ═══ The set and query methods can be divided into four different groups of methods: o Instance query methods o Instance set methods o Class query methods o Class set methods. This section describes each of them and provides sample code fragments. It also explains their role, and whether or not they are used to override methods. ═══ 9.2.1. Instance Query Methods ═══ The instance query methods are used to define the properties of an instance of your object. You would normally override these methods to define the unique properties of the instance of the object. For example, you might override wpclsQueryStyle if you want to prevent all instances of your object from being deleted. However, you would override wpQueryStyle to prevent only certain instances of this object from being deleted, as shown in the following sample code: ULONG SOMLINK myfdr_wpQueryStyle(MyFolder *somSelf) { ULONG ulStyle; ULONG ulAttr; MyFolderMethodDebug("MyFolder","myfdr_wpQueryStyle"); ulStyle = parent_wpQueryStyle(somSelf); ulAttr = _wpQueryAttr( somSelf ); if (ulAttr & FILE_READONLY) { ulStyle |= OBJSTYLE_NODELETE; } return ulStyle; } ═══ 9.2.2. Instance Set Methods ═══ The instance set methods are used to modify the properties of a specific object instance. You would not normally override these methods but would call these methods to change the behavior of the corresponding instance query method or the behavior of the object. For example, you might call wpSetIcon to change the current icon for your object, as shown in the following sample code: . . . /* Load the icon from the resource file */ hptrIcon = WinLoadPointer(HWND_DESKTOP,vhmod,IDP_Folder3); /* Make this the current icon for the object */ _wpSetIcon(somSelf,hptrIcon); . . . ═══ 9.2.3. Class Query Methods ═══ The class query methods are used to define the properties of an object class. You would normally override these methods to define the unique properties of the class object. For example, you would override wpclsQueryTitle to provide a unique title for your object class. If you were defining a class called MyFolder, as a subclass of WPFolder, you might supply the following method to make the default title for all instances (including the template) of the MyFolder object "My Folder". PSZ SOMLINK myfdrM_wpclsQueryTitle(M_MyFolder *self) { M_MyFolderMethodDebug("M_MyFolder","myfdrM_wpclsQueryTitle"); return ("My Folder"); } If you want to provide a unique icon for all instances of your class, you would override wpclsQueryIconData, as shown in the following sample code: ULONG SOMLINK myfdrM_wpclsQueryIconData(M_MyFolder *self, PICONINFO pIconInfo) { M_MyFolderMethodDebug("M_MyFolder","myfdrM_wpclsQueryIconData"); if (pIconInfo) { /* * vhmod is a global variable containing the * module handle for your .DLL * IDP_MyFolder is the resource number for the class icon */ pIconInfo->fFormat = ICON_RESOURCE; pIconInfo->hmod = vhmod; pIconInfo->resid = IDP_MyFolder; } return (sizeof(ICONINFO)); } If your class is a subclass of WPFolder (as in the above example) and you want to provide an animation icon, that is the icon that is displayed when an instance of your folder object is opened, you would override wpclsQueryIconDataN, as shown in the following sample code: ULONG SOMLINK fdrM_wpclsQueryIconDataN(M_MyFolder *self, PICONINFO pIconInfo, ULONG ulIconIndex) { ULONG ulReturn; M_MyFolderMethodDebug("M_MyFolder","myfdrM_wpclsQueryIconDataN"); switch (ulIconIndex) { case 0: /* Return the information for the closed folder icon */ ulReturn = _wpclsQueryIconData(self,pIconInfo); break; case 1: /* Return the information for the open folder icon */ if (pIconInfo) { pIconInfo->fFormat = ICON_RESOURCE; pIconInfo->hmod = vhmod; pIconInfo->resid = IDP_MyFolder2; } ulReturn = sizeof(ICONINFO); break; default: /* Invalid index value specified */ ulReturn = 0; } return (ulReturn); } ═══ 9.2.4. Class Set Methods ═══ The class set methods are used to modify the properties of an object class. You would not normally override these methods but would call these methods to change the behavior of the corresponding class query method. For example, you might call wpclsSetError to define an error code to be returned by the next call to wpclsQueryError, as shown in the following sample code: /* Set the class error code */ _wpclsSetError(_MyFolder,0x1234); . . . /* Retrieve the last class error code */ ulLastError = _wpclsQueryError(_MyFolder); ═══ 10. Object Initialization and Termination: Setup/Cleanup Methods ═══ The Workplace Shell provides methods that you can use to setup the characteristics and behaviors of an object. Likewise, it also provides methods that you can use to cleanup after an object is no longer in use. This chapter provides information on setup and cleanup methods that are available in the Workplace Shell. ═══ 10.1. About Setup/Cleanup Methods ═══ Setup and cleanup methods support object initialization and termination. The setup methods are used to set up object characteristics during creation of the object. The cleanup methods are used to ensure that memory and other resources allocated to an object are freed when the object is no longer in use. ═══ 10.1.1. Create the Object ═══ When an object is created, by using WinCreateObject for example, wpclsNew is called. You will likely not be concerned with this method because it performs functions such as allocating memory for the object, getting SOM to initialize the object, and creating the persistent image of the object as file system attributes or .INI file entries. You will be interested in methods that it invokes. These include wpInitData and wpSetupOnce. ═══ 10.1.2. Initialize the Object's Instance Data ═══ The wpInitData method is called from WPObject's override of somDefaultInit immediately after the memory for the object has been allocated. The allocated memory is zero filled. If the zero initialization is not adequate for the object instance data for your class, override this method and set the instance variable values appropriately. The wpInitData method is called whenever the object is instantiated, whether it be during initial object creation or awakening it from dormancy. In the latter case, wpRestoreState is invoked after wpInitData. ═══ 10.1.3. Setup the Object's Characteristics and Behaviors ═══ The wpSetupOnce method is called during initial object creation following wpInitData and the creation of the persistent image. It is not called when an object is awakened from dormancy. The primary purpose of wpSetupOnce is to: o Call wpSetup to set the object characteristics and behaviors based on the setup string input to WinCreateObject. o Perform non-setup string initialization that cannot be done during the wpInitData processing. The non-setup string initialization may have been deferred because it required existence of the persistent image or because it was data other than instance data that required initialization. Override wpSetupOnce only if your class has non-setup string initialization to perform because WPObject wpSetupOnce calls wpSetup. Override wpSetup if your object class has defined unique setup string keywords or keyword values. The wpSetup method is also invoked as a result of WinSetObjectData being called on an existing object. The wpScanSetupString method exists as a helper routine for parsing values from the setup string. ═══ 10.1.4. Setup and Query the Object's State ═══ One of the last steps of object creation or awakening is setting the object to the initialized state. The wpIsObjectInitialized method queries the object for this indication. The last step is the invocation of wpObjectReady. This is a notification to the object indicating completion of the creation or awakening operation. Override this method if you want to receive this notification. The wpObjectReady method indicates when it is safe to call wpSaveDeferred on a newly instantiated object. ═══ 10.1.5. Uninitialize the Object ═══ The wpUnInitData method is the opposite of wpInitData. It is called by WPObject's override of somDestruct just prior to freeing the object's memory, during the process of making the object dormant or destroying it. The object's instance data, and memory allocated via wpAllocMem, are automatically deallocated. Override this method if your object has allocated additional resources since the last time it was awakened. ═══ 10.1.6. Destroy the Object ═══ The wpFree method is the opposite of wpclsNew. It destroys the persistent image of the object and frees the object's memory. Override this method to free resources you have allocated that are associated with the persistent image of the object. ═══ 10.1.7. Workplace Shell Setup Strings ═══ Classes can define keynames and values that affect the behavior of their objects. Use keynames with setup methods as follows: o To set a certain behavior during object creation, specify the keyname in the setup string of WinCreateObject. o To change the behavior of an existing object, specify the keyname in the setup string of WinSetObjectData. Because keynames have default values, setup strings are not required for these calls. Every class may define its own set of keynames and values. The Workplace Object Classes section contains the definition of keynames for all classes. Keynames and the values supported by the WPObject class are listed in the following table: ┌──────────────────┬────────────┬──────────────────────────────┐ │Keyname │Value │Description │ ├──────────────────┼────────────┼──────────────────────────────┤ │CCVIEW │DEFAULT │Uses the default value of the │ │ │ │concurrent view setting of the│ │ │ │system, when the user selects │ │ │ │open. This is the default │ │ │ │value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │YES │Creates new views of the │ │ │ │object every time the user │ │ │ │selects open. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Resurfaces open views of │ │ │ │object, when the user selects │ │ │ │open. │ ├──────────────────┼────────────┼──────────────────────────────┤ │DEFAULTVIEW │DEFAULT │Sets the default open view to │ │ │ │the object's class default │ │ │ │view as returned by │ │ │ │wpclsQueryDefaultView. This is│ │ │ │the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │SETTINGS │Sets the default open view to │ │ │ │the Settings view. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │ID │Sets the default open view to │ │ │ │the "id" of a user-added view │ │ │ │(0 - 9). │ ├──────────────────┼────────────┼──────────────────────────────┤ │HELPLIBRARY │filename │Sets the help library. │ ├──────────────────┼────────────┼──────────────────────────────┤ │HELPPANEL │id │Sets the object's default help│ │ │ │panel. This is equivalent to │ │ │ │calling wpSetDefaultHelp. │ ├──────────────────┼────────────┼──────────────────────────────┤ │HIDEBUTTON │YES │Views of this object have a │ │ │ │hide button as opposed to a │ │ │ │minimize button. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Views of this object have a │ │ │ │minimize button as opposed to │ │ │ │a hide button. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │ │The default is the current │ │ │ │system Button appearance for │ │ │ │windows setting. This cannot │ │ │ │be specified here. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ICONFILE │filename │Sets the object's icon. This │ │ │ │is equivalent to calling │ │ │ │wpSetIconData. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ICONPOS │x, y │Sets the object's initial icon│ │ │ │position in a folder. The x │ │ │ │and y values represent the │ │ │ │position in the folder in │ │ │ │percentage coordinates. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ICONRESOURCE │id, module │Sets the object's icon. This │ │ │ │is equivalent to calling │ │ │ │wpSetIconData. The "id" is the│ │ │ │icon resource ID in the │ │ │ │dynamic link library (DLL) │ │ │ │"module". │ ├──────────────────┼────────────┼──────────────────────────────┤ │MINWIN │HIDE │Hides views of object, when │ │ │ │the minimize button is │ │ │ │selected. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │VIEWER │Minimizes views of the object │ │ │ │to Minimize window to viewer, │ │ │ │when the minimize button is │ │ │ │selected. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │DESKTOP │Minimizes views of the object │ │ │ │to Minimize window to Desktop,│ │ │ │when the minimize button is │ │ │ │selected. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │ │The default is the current │ │ │ │Minimize button setting. This │ │ │ │cannot be specified here. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOCOPY │YES │Users cannot copy objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOCOPY style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can copy objects. This │ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NODELETE │YES │Users cannot delete objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NODELETE style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can delete objects. This│ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NODRAG │YES │Users cannot drag objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NODRAG style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can drag objects. This │ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NODROP │YES │No other objects can be │ │ │ │dropped on this object. This │ │ │ │is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NODROPON style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Objects can be dropped on this│ │ │ │object. This is the default │ │ │ │value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOLINK │YES │Objects cannot be linked. This│ │ │ │is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOLINK style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Objects can be linked. This is│ │ │ │the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOMOVE │YES │Users cannot move objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOMOVE style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can move objects. This │ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOPRINT │YES │Users cannot print objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOPRINT style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can print objects. This │ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NORENAME │YES │Users cannot rename objects. │ │ │ │This is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NORENAME style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can rename objects. This│ │ │ │is the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOSETTINGS │YES │Users cannot open the object's│ │ │ │Settings notebook. This is │ │ │ │equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOSETTINGS style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can open the object's │ │ │ │Settings notebook. This is the│ │ │ │default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOSHADOW (Same as │YES │Users cannot create shadows of│ │NOLINK) │ │objects. This is equivalent to│ │ │ │calling wpSetStyle with the │ │ │ │OBJSTYLE_NOLINK style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users can create shadows of │ │ │ │objects. This is the default │ │ │ │value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │NOTVISIBLE │YES │Objects are not visible. This │ │ │ │is equivalent to calling │ │ │ │wpSetStyle with the │ │ │ │OBJSTYLE_NOTVISIBLE style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Objects are visible. This is │ │ │ │the default value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │OBJECTID │ │Sets a persistent ID for the │ │ │ │object. The OBJECTID can be │ │ │ │used to obtain a pointer or │ │ │ │handle to the object by │ │ │ │calling wpclsQueryObject or │ │ │ │WinQueryObject. An OBJECTID is│ │ │ │any unique string preceded │ │ │ │with a < and terminated with a│ │ │ │>. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │ │The default is to not have an │ │ │ │ID. │ ├──────────────────┼────────────┼──────────────────────────────┤ │OPEN │SETTINGS │Opens settings view when │ │ │ │object is created or when │ │ │ │WinSetObjectData is called. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │DEFAULT │Opens the default view when an│ │ │ │object is created or when │ │ │ │WinSetObjectData is called. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │ │The default is to not open a │ │ │ │view. │ ├──────────────────┼────────────┼──────────────────────────────┤ │TEMPLATE │YES │Users can create object │ │ │ │template. This is equivalent │ │ │ │to calling wpSetStyle with the│ │ │ │OBJSTYLE_TEMPLATE style. │ ├──────────────────┼────────────┼──────────────────────────────┤ │ │NO │Users cannot create object │ │ │ │template. This is the default │ │ │ │value. │ ├──────────────────┼────────────┼──────────────────────────────┤ │TITLE │Title │Sets the object's title. This │ │ │ │is equivalent to calling │ │ │ │wpSetTitle. │ └──────────────────┴────────────┴──────────────────────────────┘ The following code fragments is an example of WPObject setup string: PSZ pszSetupString = "TITLE = MYObject;" "ICONFILE = MYOBJ.ICO;" "OBJECTID = "; ═══ 10.2. Using Setup/Cleanup Methods ═══ This section describes how the setup and cleanup methods relate to one another using sample code fragments. Note: The sample code fragments in this section are part of a complete program that provides a new object class, Stack, whose instances implement standard programming push down stacks. The program is illustrated in Sample Code for Setup/Cleanup Methods. The stack is implemented as a linked list of entries with the head of the list being the top of the stack. The following code fragments shows the content of the stack elements and the stack instance data: typedef struct _STACKENTRY { PSTACKENTRY pNext; BYTE ReserveZeros[8]; ULONG cbEntry; BYTE Entry[1]; } STACKENTRY *PSTACKENTRY; BOOL bInitialized; // Initialization flag PSTACKENTRY pStackTop; // Head of stack linked list HMTX hmtxStack; // Stack serialization semaphore ═══ 10.2.1. Initializing the Object's Instance Data ═══ The wpInitData method initializes the Stack's instance data. Zero initialization is statisfactory for the stack top pointer (pStackTop), so there is nothing to do with respect to the instance data. However, I will take this opportunity to increment the awake stack instance count being maintained by the class because I want to decrement it in wpUnInitData. There are three additional items to note when overriding wpInitData: 1. The wpInitData method is invoked prior to the determination or restoration of an object's state. It is therefore necessary to be extremely careful about what other instance methods are called. It is best to call none unless you wrote them. 2. It is safest to call the parent's wpInitData before doing your own initialization. 3. If it is possible for this class to be a common ancestor in a multiple inheritance scenario, then this method needs to be written such that multiple invocations are handled. For example, if a class named Stack23 was derived from classes Stack2 and Stack3 which in turn were subclasses of Stack, that situation would exist. Not all Workplace Shell classes (WP*) currently take this precaution. Therefore, it is advisable to not inherit from more than one Workplace Shell class. Using SOM initializers and destructors is an alternative to overriding wpInitData in the multiple inheritance situation. The following sample code shows the use of wpInitData: SOM_Scope void SOMLINK stk_wpInitData( Stack *somSelf) // In - pointer to the object { StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpInitData"); parent_wpInitData(somSelf); if (!(_bInitialized)) { _bInitialized = TRUE; _clsIncObjectCount(_somGetClass(somSelf), STK_AWAKECOUNT); } /* Endif */ return; } // End stk_wpInitData ═══ 10.2.2. Initializing a Newly Created Object ═══ The wpSetupOnce method is called once during the creation of an object. I will push one item onto the stack. Unless popped by the setup string, every newly created stack will have this item. The following sample code shows the use of wpSetupOnce: SOM_Scope BOOL SOMLINK stk_wpSetupOnce( Stack *somSelf, // In - pointer to the object PSZ pszSetupString) // The method returns the value: // TRUE = successful // FALSE = error { PSZ pszStackItem = "***** BOTTOM OF STACK *****"; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpSetupOnce"); _Push(somSelf, pszStackItem, strlen(pszStackItem) + 1); return (parent_wpSetupOnce(somSelf, pszSetupString)); } // End stk_wpSetupOnce ═══ 10.2.3. Setting the Object's Characteristics and Behaviors ═══ Invoking wpSetupOnce parent causes wpSetup to be called. Two new keywords, PUSHITEM and POPITEM, have been defined for this class to push and pop items from the stack. This method is invoked when an object is created and when WinSetObjectData is called. Note the use of wpIsObjectInitialized and wpSaveDeferred to write the persistent image to the .INI file, if called as a result of WinSetObjectData. The wpScanSetupString method searches a setup string for a given keyname and returns its corresponding value. It also has a feature which returns just the length of the value when passed NULL as a pointer to the value buffer. Keynames and their values are separated by semicolons in the setup string. The escape character ( ^ ) followed by a semicolon can be used to represent a semicolon, if one is required in a keyname value specification. The following code fragments shows an example of a setup string for a stack object: PSZ pszSetupString = "TITLE = MyStack;" "OBJECTID = ;" "PUSHITEM = Pushed by Setup" The following sample code shows the use of wpSetup: SOM_Scope BOOL SOMLINK stk_wpSetup( Stack *somSelf, // In - pointer to the object PSZ pszSetupString) // The method returns the value: // TRUE = successful // FALSE = error { BOOL bSaveObject = FALSE; BOOL bStatus; ULONG cbValue; PSZ pszValue; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpSetup"); bStatus = parent_wpSetup(somSelf, pszSetupString); if (bStatus && pszSetupString && *pszSetupString) { // // Process PUSHITEM // if (_wpScanSetupString(somSelf, pszSetupString, "PUSHITEM", NULL, &cbValue)) { pszValue = (PSZ)_wpAllocMem(somSelf, cbValue, NULL); bStatus = FALSE; if (pszValue) { bStatus = _wpScanSetupString(somSelf, pszSetupString, "PUSHITEM", pszValue, &cbValue); if (bStatus) { bStatus = _Push(somSelf, pszValue, cbValue); bSaveObject = bStatus; } /* Endif */ _wpFreeMem(somSelf, (PBYTE)pszValue); } /* Endif */ } /* Endif */ // // Process POPITEM // if (bStatus && _wpScanSetupString(somSelf, pszSetupString, "POPITEM", NULL, &cbValue)) { bStatus = FALSE; if (_Pop(somSelf, NULL, &cbValue)) { pszValue = (PSZ)_wpAllocMem(somSelf, cbValue, NULL); if (pszValue) { bStatus = _Pop(somSelf, pszValue, &cbValue); bSaveObject = bStatus; _wpFreeMem(somSelf, (PBYTE)pszValue); } /* Endif */ } /* Endif */ } /* Endif */ if (bSaveObject && _wpIsObjectInitialized(somSelf)) { // // Save the object to the INI file // _wpSaveDeferred(somSelf); } /* Endif */ } /* Endif */ return(bStatus); } // End stk_wpSetup ═══ 10.2.4. Notifying the Object Is Ready ═══ The invocation of wpObjectReady is a signal that the object creation or awakening is complete. The following sample code uses this method to increment the persistent object count: SOM_Scope void SOMLINK stk_wpObjectReady( Stack *somSelf, // In - pointer to the object ULONG ulCode, // In - type of operation completed WPObject *refObject) // In - pointer to the source // object, if copy/shadow create { // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpObjectReady"); parent_wpObjectReady(somSelf, ulCode, refObject); if (!(ulCode & OR_AWAKE)) { _clsIncObjectCount(_somGetClass(somSelf), STK_PERSISTENTCOUNT); } /* Endif */ return; } // End stk_wpObjectReady ═══ 10.2.5. Uninitializing the Object ═══ The wpUnInitData method is executed just prior to deallocation of the object's memory during the process of making the object dormant or its permanent destruction. We want to deallocate all the memory and other resources allocated during this instantiation of the object. Memory allocated via wpAllocMem() is freed automatically by one of the Workplace Shell ancestors, so we need not do it here. As in the override of wpUnInitData, the multiple inheritance issue should be addressed here as well. The following sample code shows the use of wpUnInitData: SOM_Scope void SOMLINK stk_wpUnInitData( Stack *somSelf) // In - pointer to the object { StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpUnInitData"); if (_bInitialized) { _bInitialized = FALSE; _clsDecObjectCount(_somGetClass(somSelf), STK_AWAKECOUNT); } /* Endif */ parent_wpUnInitData(somSelf); } // End stk_wpUnInitData ═══ 10.2.6. Destroying the Object ═══ The wpFree method is generally overridden by storage classes such as WPFileSystem and WPAbstract, which provide for the permanent storage of an object's instance data. In addition, if you have an application that needs to destroy an object, call wpDelete rather than wpFree since it provides the user a chance to confirm the deletion. In this example, wpFree is overridden so that a count of stack object instances can be maintained. It is important that the somSelf pointer for the object not be used again following the call to parent_wpFree. The following sample code shows the use of wpFree: SOM_Scope BOOL SOMLINK stk_wpFree( Stack *somSelf) // In - pointer to the object // The method returns the value // TRUE = successful // FALSE = error { BOOL bStatus; SOMClass *Class; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpFree"); Class = _somGetClass(somSelf); bStatus = parent_wpFree(somSelf); if (bStatus) { _clsDecObjectCount(Class, STK_PERSISTENTCOUNT); } /* Endif */ return(bStatus); } // End stk_wpFree ═══ 10.3. Sample Code for Setup/Cleanup Methods ═══ This section illustrates a complete setup/cleanup sample program. The Workplace Shell Stack object is a sample Workplace Shell SOM application that demonstrates the use of the setup and cleanup methods. The complete program provides a new object class, Stack, whose instances implement standard programming push down stacks. WPAbstract is the parent class of the Stack class providing persistence of the stack entries, via the OS2.INI file. The Stack class also maintains the number of permanent object instances and currently awake objects (instantiated in memory). A Settings notebook page has been added to each object allowing the user to: o View a stack's contents o Push new items onto the stack o Pop existing items from the stack. The awake and total object counts are also displayed on each object's new notebook page. The following figure shows the Stack Settings notebook: ═══ 10.3.1. Pushing Items onto the Stack ═══ To push a new item onto the top of the stack, enter a text string in the New item to push field and click on the Push push button. The pushed item will appear at the top of the list. ═══ 10.3.2. Popping Items from the Stack ═══ To pop the top item from the stack just click on the Pop push button. The popped item will be removed from the list and will appear in the New item to push field. ═══ 10.3.3. Setup/Cleanup Application Sample Code ═══ Several parts of this program are explained in Using Setup/Cleanup Methods. The setup/cleanup application includes the following files: File Name Description WPSTACK.IDL Class interface definition WPSTACK.C Source code WPSTACK.RCH Resource header WPSTACK.RC Resource definition WPSTACK.IPF Stack help source WPSTACK.MAK Stack make file for building the application. ═══ 10.3.3.1. Class Definition File for Stack ═══ The following sample illustrates the class interface definition file (IDL): //# CLASS: Stack //# //# CLASS HIERARCHY: //# //# SOMObject //# └───WPObject //# └───WPAbstract //# └───Stack //# #ifndef wpstack_idl #define wpstack_idl #include "wpabs.idl" typedef somToken PSTACKENTRY; //# Dummy typedef for instance variable interface M_Stack; interface Stack : WPAbstract { ULONG InsertStackPage(in HWND hwndDlg); //# PARAMETERS: //# HWND hwndDlg // In - notebook dialog window handle //# ULONG return // Out - 0 = error occurred, else page # //# //# DESC: Adds the new Settings notebook page. BOOL Lock(); //# PARAMETERS: //# BOOL return // Out - TRUE = successful //# FALSE = errror //# //# DESC: Lock the stack using a mutex semaphore so we don't have //# to worry about multiple threads messing up the linked list. BOOL Pop(in PVOID pBuffer, inout ULONG pcbBuffer); //# PARAMETERS: //# PVOID pBuffer, // In - pointer to buffer for popped item //# PULONG pcbBuffer); // InOut - size in bytes of pop buffer (in), //# // size actually returned (out) //# BOOL return // Out - TRUE = successful //# FALSE = errror //# DESC: Pops an entry from the stack. BOOL Push(in PVOID pNewItem, in ULONG cbNewItem); //# PARAMETERS: //# PVOID pNewItem, // In - pointer to the item to push //# ULONG cbNewItem // In - size in bytes of item to push //# BOOL return // Out - TRUE = successful //# FALSE = errror //# DESC: Pushes an entry onto the stack. BOOL Unlock(); //# PARAMETERS: //# BOOL return // Out - TRUE = successful //# FALSE = errror //# //# DESC: Unlock the stack, releasing the mutex semaphore. #ifdef __SOMIDL__ implementation { releaseorder: InsertStackPage, Lock, Pop, Push, Unlock; /* * Class modifiers */ functionprefix = stk_; majorversion = 1; minorversion = 2; filestem = wpstack; metaclass = M_Stack; callstyle = oidl; dllname = "wpstack.dll"; /* * Internal instance variables */ BOOL bInitialized; PSTACKENTRY pStackTop; HMTX hmtxStack; /* * Passthru to the .IH file the following: */ passthru C_ih = "#define STK_APPLICATION \"wpstack class\"" "#define STK_PERSISTENTCOUNTKEY \"object count\"" "#define MPNULL (MPFROMP( NULL ))" "#define MPZERO (MPFROMSHORT( 0 ))" "#define MRTRUE (MRFROMSHORT( (SHORT) TRUE ))" "#define MRFALSE (MRFROMSHORT( (SHORT) FALSE ))" "" "typedef struct _STACKENTRY" "{" " struct _STACKENTRY *Next;" " BYTE ReserveZeros[8];" " ULONG cbEntry;" " BYTE Entry[1];" "} STACKENTRY, *PSTACKENTRY;" ""; /* * Passthru to the .H file the following: */ passthru C_h = "#define STK_AWAKECOUNT 1" "#define STK_PERSISTENTCOUNT 2" ""; /* * Method modifiers */ wpAddSettingsPages: override; wpFree: override; wpInitData: override; wpObjectReady: override; wpRestoreState: override; wpSaveState: override; wpSetup: override; wpSetupOnce: override; wpUnInitData: override; }; #Endif /* __SOMIDL__ */ }; interface M_Stack : M_WPAbstract { ULONG clsDecObjectCount(in ULONG ulCountType); //# PARAMETERS: //# ULONG ulCountType // In - STK_AWAKECOUNT, //# STK_PERSISTENTCOUNT //# ULONG return // Out - new count value //# //# DESC: Decrements the number of defined object instances. ULONG clsIncObjectCount(in ULONG ulCountType); //# PARAMETERS: //# ULONG ulCountType // In - STK_AWAKECOUNT, //# STK_PERSISTENTCOUNT //# ULONG return // Out - new count value //# //# DESC: Increments the number of defined object instances. HMODULE clsQueryModuleHandle(); //# PARAMETERS: HMODULE return // Out - DLL module handle //# //# DESC: Gets resource module handle. ULONG clsQueryObjectCount(in ULONG ulCountType); //# PARAMETERS: //# ULONG ulCountType // In - STK_AWAKECOUNT, //# STK_PERSISTENTCOUNT //# ULONG return // Out - count of awake/persistent instances //# //# DESC: Returns the current number of defined object instances. #ifdef __SOMIDL__ implementation { releaseorder: clsDecObjectCount, clsIncObjectCount, clsQueryModuleHandle, clsQueryObjectCount; /* * Class modifiers */ functionprefix = stkM_; majorversion = 1; minorversion = 2; filestem = wpstack; callstyle = oidl; dllname = "wpstack.dll"; /* * Internal instance variables */ HMODULE hmod; /* Resource module handle */ ULONG ulAwakeCount; /* No. of stack instances in memory */ ULONG ulPersistentCount; /* Total number of stack instances */ /* * Method modifiers */ wpclsInitData: override; wpclsQueryDefaultHelp: override; wpclsQueryDefaultView: override; wpclsQueryIconData: override; }; #Endif /* __SOMIDL__ */ }; #Endif /* wpstack_idl */ ═══ 10.3.3.2. Source Code for Stack ═══ The following sample illustrates the source code (C): // Description...... M_Stack, Stack // // SOMObject // └───WPObject // └───WPAbstract // └───Stack // // This class implements a persistent stack whose data is saved in the // OS2.INI file by inheritance from WPAbstract. // // Instance Methods.......... // // InsertStackPage introduced // Lock introduced // Pop introduced // Push introduced // Unlock introduced // wpAddSettingsPages override // wpFree override // wpInitData override // wpObjectReady override // wpRestoreState override // wpSaveState override // wpSetup override // wpSetupOnce override // wpUnInitData override // // Class Methods.......... // // clsDecObjectCount introduced // clsIncObjectCount introduced // clsQueryModuleHandle introduced // clsQueryObjectCount introduced // wpclsInitData override // wpclsQueryDefaultHelp override // wpclsQueryDefaultView override // wpclsQueryIconData override // // Non-Method Functions....... // // DialogProc // // ******************************************************************* #ifndef SOM_Module_wpstack_Source #define SOM_Module_wpstack_Source #endif #define Stack_Class_Source #define M_Stack_Class_Source #include "stdlib.h" #include "string.h" #define INCL_PM #define INCL_DOS #define INCL_DOSERRORS #define INCL_DEV #define INCL_WPCLASS #define INCL_WINWORKPLACE #include "os2.h" #include "wpstack.rch" #include "wpstack.ih" // // Forward procedure declarations // MRESULT EXPENTRY DialogProc(HWND, ULONG, MPARAM, MPARAM); // // Global variables // PSZ vpszClassName = "Stack"; PSZ vpszHelpLibrary = "wpstack.hlp"; // ********************************************************************* // // METHOD NAME: stk_InsertStackPage // // FUNCTION: Inserts the new page into the Settings notebook. // This method exists so that subclassers can remove // or replace this page. // //********************************************************************** SOM_Scope ULONG SOMLINK stk_InsertStackPage( Stack *somSelf, // In - pointer to the object HWND hwndDlg) // In - notebook window handle // Method return value out - 0 = error, otherwise new page ID { PAGEINFO pi; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_InsertStackPage"); memset((PCH) &pi, 0, sizeof(PAGEINFO)); pi.cb = sizeof(PAGEINFO); pi.hwndPage = NULLHANDLE; pi.usPageStyleFlags = BKA_MAJOR; pi.usPageInsertFlags = BKA_FIRST; pi.pfnwp = DialogProc; pi.resid = _clsQueryModuleHandle(_Stack); pi.dlgid = DLG_STYLE; pi.pszName = "~Stack"; pi.pCreateParams = somSelf; pi.pszHelpLibraryName = vpszHelpLibrary; return(_wpInsertSettingsPage(somSelf, hwndDlg, &pi)); } // End stk_InsertStackPage // ********************************************************************* // // METHOD NAME: stk_Lock // // FUNCTION: Locks the stack using a mutex semaphore so it does not // have to worry about multiple threads messing up the // linked list. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_Lock( Stack *somSelf) // In - pointer to the object // Method return value out - TRUE = successful, False = error { ULONG rc; QMSG qmsg; MQINFO mqinfo; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Lock"); if (!_hmtxStack) { rc = DosCreateMutexSem(NULL, &_hmtxStack, 0, TRUE); } else { rc = DosRequestMutexSem(_hmtxStack,100); if (rc) { if (WinQueryQueueInfo(HMQ_CURRENT,&mqinfo,sizeof(MQINFO))) { // // For a PM process/thread, do a fake WinMsgSemWait // while (rc) { if (rc==ERROR_TIMEOUT) { WinPeekMsg(WinQueryAnchorBlock(HWND_DESKTOP), &qmsg, NULLHANDLE, 0,0, PM_NOREMOVE); /* For example, */ /* fake a WinMsgSemWait */ } /* Endthen */ else { break; } /* Endif */ rc = DosRequestMutexSem(_hmtxStack, 100); } /* Endwhile */ } /* Endthen */ else { // // For a non PM process/thread, just block on the semaphore // rc = DosRequestMutexSem(_hmtxStack, SEM_INDEFINITE_WAIT); } /* Endif */ } /* Endif */ } /* Endif */ return(!rc); } // End stk_Lock // ********************************************************************* // // METHOD NAME: stk_Pop // // FUNCTION: Pops an item from the stack. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_Pop( Stack *somSelf, // In - pointer to the object PVOID pBuffer, // In - pointer to the buffer for popped item. // NULL means return the buffer's size PULONG pcbBuffer) // InOut - size in bytes of the pop buffer (in), // size actually returned (out) // Method return value out - TRUE = successful, FALSE = error { BOOL bSem; PSTACKENTRY pNextEntry; BOOL bStatus = FALSE; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Pop"); /* * pStackTop is an instance variable, initialized to NULL, * which points to the top (first) entry * on the stack (list). */ bSem = _Lock(somSelf); // Semaphore that protects the stack chain if (_pStackTop) { if (pBuffer) { if (*pcbBuffer >= _pStackTop->cbEntry) { memcpy(pBuffer, _pStackTop->Entry, _pStackTop->cbEntry); *pcbBuffer = _pStackTop->cbEntry; pNextEntry = _pStackTop->Next; bStatus = _wpFreeMem(somSelf, (PBYTE)_pStackTop); if (bStatus) { _pStackTop = pNextEntry; } /* Endif */ } /* Endif */ } /* Endthen */ else { *pcbBuffer = _pStackTop->cbEntry; bStatus = TRUE; } /* Endif */ } /* Endif */ if (bSem) _Unlock(somSelf); return(bStatus); } // End stk_Pop // ********************************************************************* // // METHOD NAME: stk_Push // // FUNCTION: Pushes an item onto the stack. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_Push( Stack *somSelf, // In - pointer to the object PVOID pNewItem, // In - pointer to the item to push ULONG cbNewItem) // In - size in bytes of item to push // Method return value out - TRUE = successful, FALSE = error { BOOL bSem; PSTACKENTRY pNewEntry; BOOL bStatus = FALSE; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Push"); pNewEntry = (PSTACKENTRY)_wpAllocMem(somSelf, cbNewItem + sizeof(STACKENTRY) - sizeof(BYTE), NULL); if (pNewEntry) { /* * pStackTop is an instance variable, initialized to NULL, * which points to the top (first) entry * on the stack (list) */ memset(pNewEntry, 0, sizeof(STACKENTRY)); bSem = _Lock(somSelf); // Semaphore protect the stack chain. pNewEntry->Next = _pStackTop; _pStackTop = pNewEntry; if (pNewItem && cbNewItem) { pNewEntry->cbEntry = cbNewItem; memcpy(pNewEntry->Entry, pNewItem, cbNewItem); } /* Endif */ if (bSem) _Unlock(somSelf); bStatus = TRUE; } /* Endif */ return(bStatus); } /* End stk_Push */ // ********************************************************************* // // METHOD NAME: stk_Unlock // // FUNCTION: Unlocks the stack, releasing the mutex semaphore. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_Unlock( Stack *somSelf) // In - pointer to the object // Method return value out - TRUE = successful, False = error. { ULONG rc = 0; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Unlock"); if (_hmtxStack) { rc = DosReleaseMutexSem(_hmtxStack); } /* Endif */ return(!rc); } // End stk_Unlock // ********************************************************************* // // METHOD NAME: stk_wpAddSettingsPages // // FUNCTION: // // Adds the new stack page by calling InsertStackPage(). This page // shows the contents of the stack and allows pushing and popping // entries. It is added on top of existing pages. // //*********************************************************************** SOM_Scope BOOL SOMLINK stk_wpAddSettingsPages( Stack *somSelf, // In - pointer to the object HWND hwndNotebook) // In - Settings notebook window handle // Method return value out - TRUE = successful, FALSE = error { // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpAddSettingsPages"); parent_wpAddSettingsPages(somSelf, hwndNotebook); return(_InsertStackPage(somSelf, hwndNotebook) != 0); } // End stk_wpAddSettingsPages // ********************************************************************* // // METHOD NAME: stk_wpFree // // FUNCTION: // // wpFree is generally overridden by storage classes such as // WPFileSystem and WPAbstract, which provide for the permanent // storage of an object's instance data. In addition, if you // are trying to destroy an object, call wpDelete rather than wpFree // since it provides a user confirmation capability. // // In this example, wpFree is overridden so that a count of stack // object instances can be maintained. It is important that the // somSelf pointer for the object not be used again following the // call to parent_wpFree. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_wpFree( Stack *somSelf) // In - pointer to the object // Method return value out - TRUE = successful, FALSE = error { BOOL bStatus; SOMClass *Class; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpFree"); Class = _somGetClass(somSelf); bStatus = parent_wpFree(somSelf); if (bStatus) { _clsDecObjectCount(Class, STK_PERSISTENTCOUNT); } /* Endif */ return(bStatus); } // End stk_wpFree // ********************************************************************* // // METHOD NAME: stk_wpInitData // // FUNCTION: // // Initializes the stack's instance data. Zero initialization is // statisfactory for the stack top pointer (pStackTop), so there is // nothing to do with respect to the instance data. However, I will take // this opportunity to increment the awake stack instance count being // maintained by the class because I want to decrement it in wpUnInitData. // There are three additional items to note when overriding wpInitData. // First, wpInitData is invoked prior to the determination or restoration // of an object's state. It is therefore necessary to be extremely // careful about what other instance methods are called. It is best to // call none unless you wrote them. // // Second, it is safest to call the parent's wpInitData method before // doing your own initialization. // // Third, if it is possible for this class to be a common ancestor in a // multiple inheritance scenario, then this method needs to be written // such that multiple invocations are handled. For example, if a class // named Stack23 was derived from classes Stack2 and Stack3 which in // turn were subclasses of Stack, that situation would exist. Not // all Workplace Shell classes (WP*.) currently take this precaution. // Therefore, it is advisable not to inherit from more than one // Workplace Shell class. Using SOM initializers and destructors is // an alternative to overriding wpInitData in the multiple // inheritance situation. // //*********************************************************************** SOM_Scope void SOMLINK stk_wpInitData( Stack *somSelf) // In - pointer to the object { StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpInitData"); parent_wpInitData(somSelf); if (!(_bInitialized)) { _bInitialized = TRUE; _clsIncObjectCount(_somGetClass(somSelf), STK_AWAKECOUNT); } /* Endif */ return; } // End stk_wpInitData // ********************************************************************* // // METHOD NAME: stk_wpObjectReady // // FUNCTION: // // Notifies that the object's creation/awakening is complete. // This example uses this method to increment the persistent // object count. // //********************************************************************** SOM_Scope void SOMLINK stk_wpObjectReady( Stack *somSelf, // In - pointer to the object ULONG ulCode, // In - type of operation completed WPObject *refObject) // In - pointer to the source object // if an object's // copy/shadow is created { // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpObjectReady"); parent_wpObjectReady(somSelf, ulCode, refObject); if (!(ulCode & OR_AWAKE)) { _clsIncObjectCount(_somGetClass(somSelf), STK_PERSISTENTCOUNT); } /* Endif */ return; } // End stk_wpObjectReady // ********************************************************************* // // METHOD NAME: stk_wpRestoreState // // FUNCTION: // // Restores the stack items from the persistent INI file storage // into the memory resident linked list pointed to by the // pStackTop instance variable. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_wpRestoreState( Stack *somSelf, // In - pointer to the object ULONG ulReserved) { ULONG i; ULONG ulItemCount; ULONG cbItem; PBYTE pItem; PSTACKENTRY pPrevItem = NULL; BOOL bStatus; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpRestoreState"); bStatus = _wpRestoreLong(somSelf, vpszClassName, 0, &ulItemCount); for (i=1; (i<=ulItemCount) && bStatus; i++) { bStatus = _wpRestoreData(somSelf, vpszClassName, i, NULL, &cbItem); if (bStatus) { pItem = _wpAllocMem(somSelf, cbItem, NULL); if (pItem) { bStatus = _wpRestoreData(somSelf, vpszClassName, i, pItem, &cbItem); if (bStatus) { if (pPrevItem) { pPrevItem->Next = (PSTACKENTRY)pItem; } /* Endthen */ else { _pStackTop = (PSTACKENTRY)pItem; } /* Endif */ pPrevItem = (PSTACKENTRY)pItem; } /* Endthen */ else { _wpFreeMem(somSelf, pItem); } /* Endif */ } /* Endif */ } /* Endif */ } /* Endfor */ return (parent_wpRestoreState(somSelf, ulReserved)); } // End stk_wpRestoreState // ********************************************************************* // // METHOD NAME: stk_wpSaveState // // FUNCTION: // // Saves the memory resident linked list to a buffer, which will be // written to a permanent INI file storage by the WPAbstract class. // The memory resident linked list is pointed to by the // pStackTop instance variable. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_wpSaveState( Stack *somSelf) // In - pointer to the object { BOOL bSem; ULONG i; ULONG ulItemCount = 0; ULONG cbItem; PSTACKENTRY pItem; BOOL bStatus; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpSaveState"); bSem = _Lock(somSelf); // Semaphore that protects the stack chain for (pItem = _pStackTop; pItem; pItem = pItem->Next, ulItemCount++){;}; bStatus = _wpSaveLong(somSelf, vpszClassName, 0, ulItemCount); for (pItem = _pStackTop, i = 1; bStatus && pItem; pItem = pItem->Next, i++) { cbItem = sizeof(STACKENTRY) + pItem->cbEntry - 1; bStatus = _wpSaveData(somSelf, vpszClassName, i, (PBYTE)pItem, cbItem); } /* Endfor */ if (bSem) _Unlock(somSelf); return(parent_wpSaveState(somSelf)); } // End stk_wpSaveState // ********************************************************************* // // METHOD NAME: stk_wpSetup // // FUNCTION: // // Two new keywords, PUSHITEM and POPITEM, have been defined for this // class to push and pop items from the stack. This method is invoked // when an object is created and when WinSetObjectData() is called. // wpIsObjectInitialized and wpSaveDeferred are used to write // the persistent image to the INI file, if they are called as a result // of WinSetObjectData. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_wpSetup( Stack *somSelf, // In - pointer to the object PSZ pszSetupString) // Method return value out - TRUE = successful, FALSE = error { BOOL bSaveObject = FALSE; BOOL bStatus; ULONG cbValue; PSZ pszValue; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpSetup"); bStatus = parent_wpSetup(somSelf, pszSetupString); if (bStatus && pszSetupString && *pszSetupString) { // // Process PUSHITEM // if (_wpScanSetupString(somSelf, pszSetupString, "PUSHITEM", NULL, &cbValue)) { pszValue = (PSZ)_wpAllocMem(somSelf, cbValue, NULL); bStatus = FALSE; if (pszValue) { bStatus = _wpScanSetupString(somSelf, pszSetupString, "PUSHITEM", pszValue, &cbValue); if (bStatus) { bStatus = _Push(somSelf, pszValue, cbValue); bSaveObject = bStatus; } /* Endif */ _wpFreeMem(somSelf, (PBYTE)pszValue); } /* Endif */ } /* Endif */ // // Process POPITEM // if (bStatus && _wpScanSetupString(somSelf, pszSetupString, "POPITEM", NULL, &cbValue)) { bStatus = FALSE; if (_Pop(somSelf, NULL, &cbValue)) { pszValue = (PSZ)_wpAllocMem(somSelf, cbValue, NULL); if (pszValue) { bStatus = _Pop(somSelf, pszValue, &cbValue); bSaveObject = bStatus; _wpFreeMem(somSelf, (PBYTE)pszValue); } /* Endif */ } /* Endif */ } /* Endif */ if (bSaveObject && _wpIsObjectInitialized(somSelf)) { // // Save the object to the INI file. // _wpSaveDeferred(somSelf); } /* Endif */ } /* Endif */ return(bStatus); } // End stk_wpSetup // ********************************************************************* // // METHOD NAME: stk_wpSetupOnce // // FUNCTION: // // This method is called once during the creation of an object. // One item is pushed onto the stack. Unless popped by the // setup string, every newly created stack will have this item. // //********************************************************************** SOM_Scope BOOL SOMLINK stk_wpSetupOnce( Stack *somSelf, // In - pointer to the object PSZ pszSetupString) // Method return value out - TRUE = successful, FALSE = error { PSZ pszStackItem = "***** BOTTOM OF STACK *****"; // StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpSetupOnce"); _Push(somSelf, pszStackItem, strlen(pszStackItem) + 1); return (parent_wpSetupOnce(somSelf, pszSetupString)); } // End stk_wpSetupOnce // ********************************************************************* // // METHOD NAME: stk_wpUnInitData // // FUNCTION: // // This method is executed just prior to the deallocation of the // object's memory, during the process of making the object dormant // or its permanent destruction. All memory and other resources allocated // during the instantiation of the object will be deallocated. Memory // allocated by wpAllocMem() will be freed automatically by one of the // Workplace Shell ancestors, so there is no need to do this here. As in // the wpInitData() override, the multiple inheritance issue should be // addressed here as well. // //********************************************************************** SOM_Scope void SOMLINK stk_wpUnInitData( Stack *somSelf) // In - pointer to the object { StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_wpUnInitData"); if (_bInitialized) { _bInitialized = FALSE; _clsDecObjectCount(_somGetClass(somSelf), STK_AWAKECOUNT); } /* Endif */ parent_wpUnInitData(somSelf); } // End stk_wpUnInitData // ********************************************************************* // // METHOD NAME: stkM_clsDecObjectCount // // FUNCTION: // // Decrements the "awake" or "persistent" object instance count // for the class. // //********************************************************************** SOM_Scope ULONG SOMLINK stkM_clsDecObjectCount( M_Stack *somSelf, // In - pointer to the class object ULONG ulCountType) // In - STK_AWAKECOUNT, // STK_PERSISTENTCOUNT // Method return value out - new count value { ULONG ulCount = 0; M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_clsDecObjectCount"); switch (ulCountType) { case STK_AWAKECOUNT: ulCount = --_ulAwakeCount; break; case STK_PERSISTENTCOUNT: ulCount = --_ulPersistentCount; // // Write this value to the INI file // PrfWriteProfileData(HINI_USERPROFILE, STK_APPLICATION, STK_PERSISTENTCOUNTKEY, &_ulPersistentCount, sizeof(ULONG)); break; default: break; } /* Endswitch */ return(ulCount); } // stkM_clsDecObjectCount // ********************************************************************* // // METHOD NAME: stkM_clsIncObjectCount // // FUNCTION: // // Increments the "awake" or "persistent" object instance count // for the class. // //********************************************************************** SOM_Scope ULONG somlink stkM_clsIncObjectCount( M_Stack *somSelf, // In - pointer to the class object ULONG ulCountType) // In - STK_AWAKECOUNT, // STK_PERSISTENTCOUNT // Method return value out - new count value { ULONG ulCount = 0; M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_clsIncObjectCount"); switch (ulCountType) { case STK_AWAKECOUNT: ulCount = ++_ulAwakeCount; break; case STK_PERSISTENTCOUNT: ulCount = ++_ulPersistentCount; // // Need to write this value to the INI file // PrfWriteProfileData(HINI_USERPROFILE, STK_APPLICATION, STK_PERSISTENTCOUNTKEY, &_ulPersistentCount, sizeof(ULONG)); break; default: break; } /* Endswitch */ return(ulCount); } // stkM_clsIncObjectCount // ********************************************************************* // // METHOD NAME: stkM_clsQueryModuleHandle // // FUNCTION: // // Returns the resource file module handle which was obtained // by wpclsInitData during the initialization process. // //********************************************************************** SOM_Scope HMODULE somlink stkM_clsQueryModuleHandle( M_Stack *somSelf) // In - pointer to the class object // Method return value out - resouce module handle { M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_clsQueryModuleHandle"); return(_hmod); } // End stkM_clsQueryModuleHandle // ********************************************************************* // // METHOD NAME: stkM_clsQueryObjectCount // // FUNCTION: // // Returns the "awake" or "persistent" object instance count // for the class. // //********************************************************************** SOM_Scope ULONG somlink stkM_clsQueryObjectCount( M_Stack *somSelf, // In - pointer to the class object ULONG ulCountType) // In - STK_AWAKECOUNT, // STK_PERSISTENTCOUNT // Method return value out - current count value { ULONG ulCount = 0; M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_clsQueryObjectCount"); switch (ulCountType) { case STK_AWAKECOUNT: ulCount = _ulAwakeCount; break; case STK_PERSISTENTCOUNT: ulCount = _ulPersistentCount; break; default: break; } /* Endswitch */ return(ulCount); } // End stkM_clsQueryObjectCount // ********************************************************************* // // METHOD NAME: stkM_wpclsInitData // // FUNCTION: // // Initializes the class data (resource file module handle). // In this case, the resouce file is linked with the code // (WPSTACK.DLL). The parent initialization is usually done first so // that some ancestor methods can be called. // //********************************************************************** SOM_Scope void somlink stkM_wpclsInitData( M_Stack *somSelf) // In - pointer to the class object { PSZ psz; somId stackId; ULONG cbValue = sizeof(ULONG); M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_wpclsInitData"); parent_wpclsInitData(somSelf); stackId = somIdFromString("Stack"); psz = _somLocateClassFile(SOMClassMgrObject, stackId, Stack_MajorVersion, Stack_MinorVersion); SOMFree(stackId); if (psz != NULL) { DosQueryModuleHandle(psz, &_hmod); } /* Endif */ // // Get the persistent object count from the INI file // PrfQueryProfileData(HINI_USERPROFILE, STK_APPLICATION, STK_PERSISTENTCOUNTKEY, &_ulPersistentCount, &cbValue); return; } // End stkM_wpclsInitData // ********************************************************************* // // METHOD NAME: stkM_wpclsQueryDefaultHelp // // FUNCTION: // // Returns the help panel DLL and ID. // //********************************************************************** SOM_Scope BOOL somlink stkM_wpclsQueryDefaultHelp( M_Stack *somSelf, // In - pointer to the class object PULONG pHelpPanelId, PSZ pszHelpLibrary) // Method return value out - TRUE = successful, FALSE = error { // M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_wpclsQueryDefaultHelp"); if (pHelpPanelId) { *pHelpPanelId = ID_HELP_STACK; } /* Endif */ if (pszHelpLibrary) { strcpy(pszHelpLibrary, vpszHelpLibrary); } /* Endif */ return(TRUE); } // End stkM_wpclsQueryDefaultHelp // ********************************************************************* // // METHOD NAME: stkM_wpclsQueryDefaultView // // FUNCTION: // // Opens the Settings view as the default. // //********************************************************************** SOM_Scope ULONG somlink stkM_wpclsQueryDefaultView( M_Stack *somSelf) // In - pointer to the class object { // M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_wpclsQueryDefaultView"); return OPEN_SETTINGS; } // End stkM_wpclsQueryDefaultView // ********************************************************************* // // METHOD NAME: stkM_wpclsQueryIconData // // FUNCTION: // // This method is overridden so that the class' objects has // a unique icon. // //********************************************************************** SOM_Scope ULONG SOMLINK stkM_wpclsQueryIconData( M_Stack *somSelf, // In - pointer to the class object PICONINFO pIconInfo ) // In - buffer for the icon data // Method return value out - size of data returned { // M_StackData *somThis = M_StackGetData(somSelf); M_StackMethodDebug("M_Stack","stkM_wpclsQueryIcon"); if (pIconInfo) { pIconInfo->fFormat = ICON_RESOURCE; pIconInfo->hmod = _clsQueryModuleHandle(somSelf); pIconInfo->resid = ID_OBJECTICON; } return sizeof(ICONINFO); } // End stkM_wpclsQueryIconData // ********************************************************************* // // PROCEDURE NAME: DialogProc // // FUNCTION: // // This is the dialog procedure for the new Settings notebook page. // //********************************************************************** MRESULT EXPENTRY DialogProc(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2) { typedef struct _WINDATA { SOMAny *somSelf; StackData *somThis; } WINDATA, *PWINDATA; MRESULT mresultWpRtnCd = MRFALSE; PWINDATA pwin = (PWINDATA) WinQueryWindowPtr(hwndDlg, QWL_USER); CHAR szNewItem[CCHMAXPATH]; ULONG cbNewItem; PSTACKENTRY pItem; BOOL bSem; switch( msg ) { case WM_INITDLG: { pwin = (PWINDATA) _wpAllocMem((SOMAny *) mp2, sizeof(WINDATA), NULL); WinSetWindowPtr(hwndDlg, QWL_USER, pwin); // // Initialize WINDATA structure // pwin->somSelf = (SOMAny *) mp2; pwin->somThis = StackGetData(pwin->somSelf); // // Display the stack object count statistics // _ltoa(_clsQueryObjectCount(_somGetClass(pwin->somSelf), STK_AWAKECOUNT), szNewItem, 10); WinSetDlgItemText(hwndDlg, DLG_AWAKECOUNT, szNewItem); _ltoa(_clsQueryObjectCount(_somGetClass(pwin->somSelf), STK_PERSISTENTCOUNT), szNewItem, 10); WinSetDlgItemText(hwndDlg, DLG_PERSISTENTCOUNT, szNewItem); // // Insert stack items into the list box // bSem = _Lock(pwin->somSelf); for (pItem = pwin->somThis->pStackTop; pItem; pItem = pItem->Next) { WinInsertLboxItem(WinWindowFromID(hwndDlg, DLG_ITEMLIST), LIT_END, pItem->Entry); } /* Endfor */ if (bSem) _Unlock(pwin->somSelf); // // Return TRUE to tell PM that we changed focus // mresultWpRtnCd = (MRESULT) TRUE; break; } /* End of case WM_INITDLG */ case WM_COMMAND: { switch(SHORT1FROMMP(mp1)) { case DLG_PUSH: /* Push pushbutton */ { szNewItem[0] = '\0'; cbNewItem = WinQueryDlgItemText(hwndDlg, DLG_NEWITEM, sizeof(szNewItem), szNewItem); if (_Push(pwin->somSelf, szNewItem, cbNewItem+1)) { WinInsertLboxItem(WinWindowFromID(hwndDlg, DLG_ITEMLIST), 0, szNewItem); _wpSaveDeferred(pwin->somSelf); // Save state to INI file } /* Endif */ break; } case DLG_POP: /* Pop pushbutton */ { szNewItem[0] = '\0'; cbNewItem = sizeof(szNewItem); if (_Pop(pwin->somSelf, szNewItem, &cbNewItem)) { cbNewItem = cbNewItem ? cbNewItem : 1; WinSetDlgItemText(hwndDlg, DLG_NEWITEM, szNewItem); WinDeleteLboxItem(WinWindowFromID (hwndDlg, DLG_ITEMLIST), 0); _wpSaveDeferred(pwin->somSelf); // Save state to INI file } /* Endif */ break; } case DLG_HELP: /* Help push button */ { _wpDisplayHelp(pwin->somSelf, ID_HELP_STACK, vpszHelpLibrary); break; } default: break; } break; } /* End of case WM_COMMAND */ case WM_DESTROY: { _wpFreeMem(pwin->somSelf, (PBYTE)pwin); mresultWpRtnCd = WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; } /* End of case WM_DESTROY */ default: { mresultWpRtnCd = WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; } // End of default: } return mresultWpRtnCd; \} #pragma info(nouse) ═══ 10.3.3.3. Resource Header File for Stack ═══ The following sample illustrates the resource header file (RCH): #define ID_OBJECTICON 255 #define ID_HELP_STACK 256 #define DLG_STYLE 100 #define DLG_AWAKECOUNT 101 #define DLG_PERSISTENTCOUNT 102 #define DLG_NEWITEM 103 #define DLG_ITEMLIST 104 #define DLG_PUSH 105 #define DLG_POP 106 #define DLG_HELP 107 The following sample illustrates the resource definition file (RC): #include #include "wpstack.rch" ICON ID_OBJECTICON WPSTACK.ICO DLGTEMPLATE DLG_STYLE LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "", DLG_STYLE, 0, 0, 224, 200, NOT FS_DLGBORDER BEGIN /* * Create output fields for stack object count statistics. * Will display them on every object. */ LTEXT "Awake Stack Count:" -1, 10, 140, 85, 8 LTEXT "" DLG_AWAKECOUNT, 100, 140, 25, 8 LTEXT "Total Stack Count:" -1, 10, 130, 85, 8 LTEXT "" DLG_PERSISTENTCOUNT, 100, 130, 25, 8 /* * Create an entry field for specifying text to push * and a list box for the current stack contents */ LTEXT "New item to push:" -1, 10, 120, 76, 8 ENTRYFIELD "", DLG_NEWITEM, 10, 105, 180, 8, ES_MARGIN LTEXT "Stack contents:", -1, 10, 90, 76, 8 LISTBOX DLG_ITEMLIST, 10, 30, 180, 54, LS_HORZSCROLL /* * Align the push button along the bottom */ PUSHBUTTON "P~ush", DLG_PUSH, 7, 7, 38, 14 PUSHBUTTON "P~op", DLG_POP, 57, 7, 38, 14 PUSHBUTTON "~Help", DLG_HELP, 107, 7, 38, 14 END END ═══ 10.3.3.4. Help Source File for Stack ═══ The following sample illustrates the help source file (IPF): :userdoc. .*-------------------------------------------------------------- .* Main window extended help panel .*-------------------------------------------------------------- .* :h1 res=256 name=PANEL_MAIN.Workplace Shell Stack Object :i1 id=abtStl.Workplace Shell Stack Object :p. The Workplace Shell Stack object is a sample Workplace Shell SOM application that demonstrates the use of Workplace Shell setup and cleanup methods. The application provides a new object class, Stack, whose instances implement standard programming push down stacks. WPAbstract is the parent class of the Stack class providing persistence of the stack entries, via the OS2.INI file. The Stack class also maintains the number of permanent object instances and currently awaken objects (instantiated in memory). :p. A Settings notebook page has been added to each object allowing the user to view a stacks contents, push new items onto the stack, and pop existing items from the stack. The awake and total object counts are also displayed on each object's new notebook page. :p. :hp2.Pushing Items onto the Stack:ehp2. :p. To push a new item onto the top of the stack, enter a text string in the input field labeled New item to push and click on the Push push button. The pushed item will appear at the top of the list. :hp2.Popping Items from the Stack:ehp2. :p. To pop the top item from the stack just click on the Pop push button. The popped item will be removed from the list and appear in the New item to push field. .* :euserdoc. ═══ 10.3.3.5. Make File for Stack ═══ The following sample illustrates the make file (MAK): .SUFFIXES: .c .obj .dll .idl .h .ih .rc .res SC = sc SCFLAGS = -maddstar -S128000 -C128000 -mnoint -v SCLIST = -s "ih;h;c;def" INCLUDE = .;d:\som\include;d:\wpshidl\h;$(INCLUDE) SMINCLUDE = .;d:\som\include;d:\wpshidl\idl;$(SMINCLUDE) LIB = d:\som\lib;e:\ibmcpp\lib;e:\toolkt21\os2lib;$(LIB) CFLAGS = -Ge- -Ss+ -C+ -Kb -Q+ -Ms LFLAGS = /MAP /NOL /NOI /EXEPACK:2 /PACKCODE /PACKDATA /FAR /ALIGN:4 b=wpstack all: $(b).dll $(b).ih $(b).hlp .c.obj: icc $(CFLAGS) $*.c $(b).dll: $(b).ih $(b).obj $(b).def $(b).res link386 $(b) $(LFLAGS),$(b).dll,$(b).map,somtk,$(b) rc $(b).res $(b).dll mapsym $(b).map $(b).obj: $(b).c $(b).h $(b).res: $(b).rc $(b).ico rc -r $(b).rc $(b).ih: $(b).idl $(SC) $(SCFLAGS) $(SCLIST) $(@B).idl $(b).hlp: $(b).ipf ipfc $(b).ipf clean: -del $(b).ih $(b).h $(b).obj $(b).dll -del $(b).map $(b).sym $(b).res $(b).def ═══ 11. Object Memory: Memory Allocation Methods ═══ The Workplace Shell provides methods which you can override to design your own memory management system, or utilize to manage memory required for objects of your application. This chapter provides information on memory management methods for Workplace Shell applications. ═══ 11.1. About Memory Allocation Methods ═══ The wpAllocMem method allocates memory for use by an object. A record of memory blocks allocated by calls to wpAllocMem is kept by adding USAGE_MEMORY type items to the object's USEITEM list. The USEITEM list is examined by wpUnInitData when the object is destroyed or made dormant to free previously allocated resources. Memory that is allocated to an object is de-allocated automatically when the object is no longer in use, assuming the memory has not already been cleaned up by the object. wpFreeMem is called to free allocated memory, even if the object is still in use. This method should be overriden to free memory that was allocated with an override method of wpAllocMem. ═══ 11.2. Using Memory Allocation Methods ═══ As an example of the way these methods may be utilized, consider the definition of a WPAbstract subclass, Stack, with the Push() and Pop() methods. The following sample code fragments show the Push() and Pop() methods using the memory allocation methods. Push() allocates space for the new item, initializes its contents and places it on the stack while Pop() removes the top item from the stack, and returns its contents. The stack is implemented as a linked list of entries with the head of the list being the top of the stack. Assume the existence of methods, Lock() and Unlock(), which protect the stack linked list in a multithread environment. Note: The sample code fragments in this section are part of a complete program that provides a new object class, Stack, whose instances implement standard programming push down stacks. The program is illustrated in "Sample Code for Setup/Cleanup Methods". #include "stack.ih" typedef struct _STACKENTRY { PSTACKENTRY pNext; BYTE ReserveZeros[8]; ULONG cbEntry; BYTE Entry[1]; } STACKENTRY; *PSTACKENTRY; /************************ wpAllocMem Method ************************/ SOM_Scope BOOL SOMLINK stk_Push( Stack *somSelf, // In - pointer to the object PVOID pNewItem, // In - pointer to the item to push ULONG cbNewItem) // In - size in bytes of item to push // The method returns the value: // TRUE = successful // FALSE = error { BOOL bSem; PSTACKENTRY pNewEntry; BOOL bStatus = FALSE; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Push"); pNewEntry = (PSTACKENTRY)_wpAllocMem(somSelf, cbNewItem + sizeof(STACKENTRY) - sizeof(BYTE), NULL); if (pNewEntry) { /* * pStackTop is an instance variable, initialized to NULL, * which points to the top (first) entry * on the stack (list) */ memset(pNewEntry, 0, sizeof(STACKENTRY)); bSem = _Lock(somSelf); // Semaphore that protects the stack chain pNewEntry->Next = _pStackTop; _pStackTop = pNewEntry; if (pNewItem && cbNewItem) { pNewEntry->cbEntry = cbNewItem; memcpy(pNewEntry->Entry, pNewItem, cbNewItem); } /* Endif */ if (bSem) _Unlock(somSelf); bStatus = TRUE; } /* Endif */ return(bStatus); } /* End stk_Push */ /************************ wpFreeMem Method *************************/ SOM_Scope BOOL SOMLINK stk_Pop( Stack *somSelf, // In - pointer to the object PVOID pBuffer, // In - pointer to buffer for popped item, // NULL means return size of buffer PULONG pcbBuffer) // InOut - size in bytes of pop buffer, // size actually returned // The method returns the value: // TRUE = successful // FALSE = error { BOOL bSem; PSTACKENTRY pNextEntry; BOOL bStatus = FALSE; StackData *somThis = StackGetData(somSelf); StackMethodDebug("Stack","stk_Pop"); /* * pStackTop is an instance variable, initialized to NULL, * which points to the top (first) entry * on the stack (list). */ bSem = _Lock(somSelf); // Semaphore that protects the stack chain if (_pStackTop) { if (pBuffer) { if (*pcbBuffer >= _pStackTop->cbEntry) { memcpy(pBuffer, _pStackTop->Entry, _pStackTop->cbEntry); *pcbBuffer = _pStackTop->cbEntry; pNextEntry = _pStackTop->Next; bStatus = _wpFreeMem(somSelf, (PBYTE)_pStackTop); if (bStatus) { _pStackTop = pNextEntry; } /* Endif */ } /* Endif */ } /* Endthen */ else { *pcbBuffer = _pStackTop->cbEntry; bStatus = TRUE; } /* Endif */ } /* Endif */ if (bSem) _Unlock(somSelf); return(bStatus); } // End stk_Pop ═══ 12. Object Mobility: Direct Manipulation Methods ═══ Direct manipulation is interaction with objects by way of a pointing device. For example, using direct manipulation, a user can move an object from one container to another by dragging an object icon from a source container and dropping it on a target container. Direct manipulation methods allow you to specify how objects that are directly effected by such a move communicate with each other. This chapter outlines the protocols of direct manipulation with respect to their interactions with the Workplace Shell. The following material is presented as a supplement to information on direct manipulation in the Presentation Manager Programming Guide - Advanced Topics. ═══ 12.1. About Direct Manipulation Methods ═══ Direct manipulation enables the user to visually drag an object (the source object) and drop it on another object (the target object) causing an interaction, or data exchange, between the objects. The Workplace Shell tracks an object being dragged, notifying target objects and windows as the source object is being dragged over them and when it is dropped on them. The Workplace Shell notifies a target object by calling the object's direct manipulation methods that process the source object being dragged and dropped. Direct manipulation methods initialize the structures that convey information about objects being moved to the target and describe images to be displayed during the Drag operation. ═══ 12.1.1. Direct Manipulation on Workplace Shell Objects ═══ Common objects are provided by the Workplace Shell for use in applications. When an icon is dragged over a Workplace Shell object, the target object sends a message to the source container to enable a direct manipulation exchange. The message explains what the target object does. Completion of a drop requires that the source and target objects share a common rendering mechanism. If the source object is not appropriate for a drop on the target and the drop is prohibited, a "do-not" symbol is shown. Workplace Shell handles standard Presentation Manager rendering mechanisms, as well as its own mechanisms, to allow easy integration of Presentation Manager applications. Workplace Shell simplifies implementation of a direct manipulation operation, handling the filling of data structures, the drag sequence, and notification of the target when a successful drop occurs. The standard direct manipulation capabilities of the Workplace Shell include Print, Delete and File Move/Copy. ═══ 12.1.2. Direct Manipulation on PM Applications ═══ For PM applications, the Workplace Shell sends DM_ messages to PM windows using the standard or enhanced direct manipulation protocols. The Workplace Shell will drag source objects rendered as OBJECT or as OS2FILE and will accept source objects rendered in the same way. The Workplace Shell also will send a DM_PRINTOBJECT message to items dropped on the printer object. Users can drag source objects over windows that an object creates. When this occurs, the Workplace Shell sends DM_ messages to these windows. Therefore, window procedures associated with the windows that the object creates must be able to process DM_ messages. Target objects are not necessarily able to process every type of source object that is dropped on them. They are, however, capable of processing more than one type of dropped source object. Printer objects, for example, cannot print binary files, but they can print both text and graphics files. Because of differing capabilities, each target object should determine if it can process the source object being dropped on it. The following table shows the direct manipulation messages that are sent to target objects and the methods that are invoked by the Workplace Shell: ┌───────────────┬─────────────────┬──────────┬──────────────────┐ │Description │Method Name │Invoked On│Message Name │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Format drag │wpFormatDragItem │Source │None │ │information │ │ │ │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Request │wpRender │Source │DM_RENDER │ │rendering │ │ │ │ │format │ │ │ │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Rendering │wpRenderComplete │Target │DM_RENDERCOMPLETE │ │request │ │ │ │ │completed │ │ │ │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Objects being │wpDragOver │Target │DM_DRAGOVER │ │dragged over │ │ │ │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Object has been│wpDrop │Source │DM_DROP │ │dropped │ │ │ │ ├───────────────┼─────────────────┼──────────┼──────────────────┤ │Drag/Drop is │wpEndConversation│Target │DM_ENDCONVERSATION│ │complete │ │ │ │ └───────────────┴─────────────────┴──────────┴──────────────────┘ The "Source" and "Target" windows in the following diagram represent windows that have been subclassed, via CnrOwnerSubclassProc, by the Workplace Shell: ┌──────────────────────────────────────────────────────┐ │ Source Target │ └──────────────────────────────────────────────────────┘ │ │ User begins drag │ │ (WM_BEGINDRAG ────────>│ │ or │ │ WM_PICKUP) │ │ │ │ │ │ wpFormatDragItem(sourceobject) │ │ │ │ DM_DRAGOVER │ .>│───────────────────────────────>│ . │ │ . │ wpDragOver(targetobject) . │ │ . │ DDR_ response │ ..│<───────────────────────────────│ │ │ User ends drag │ │ (WM_ENDDRAG)──────────>│ │ │ DM_DROP │ │───────────────────────────────>│ │ │ │ wpDrop(targetobject) │ │ ... If source rendering is indicated ... │ │ │ │ │ DM_RENDERPREPARE │ │ (If necessary) │ │<───────────────────────────────│<. │ │ . │ DM_RENDER │ . │ (If supported) │ . │<───────────────────────────────│ . │ │ . wpRender(sourceobject) │ . │ │ . │ DM_RENDERCOMPLETE │ . │───────────────────────────────>│ . │ │.. │ │ │ wpRenderComplete(targetobject) │ │ │ │ │ │ │ │ │ DM_ENDCONVERSATION │ │<───────────────────────────────│ │ │ wpEndConversation(sourceobject) ═══ 12.2. Using Direct Manipulation Methods ═══ This section shows the sequence of method flows for a typical direct manipulation operation. ═══ 12.2.1. Starting a Drag Operation ═══ Folders are containers; therefore, they receive notification from the container controls when an object is added to a container. The Workplace Shell subclasses the owner of the container control. The Workplace Shell initiates the Drag operation, calls wpFormatDragItem to fill out the data structures, and calls DrgDrag or DrgLazyDrag to perform the actual dragging. A Workplace Shell object need not invoke DrgDrag or DrgLazyDrag, since this is done automatically by the Workplace Shell when the object completes the processing of wpFormatDragItem. When the user begins to drag an object, the source object is notified by the system, which invokes the object's wpFormatDragItem. This method is used to build a DRAGITEM structure, which is passed to a potential target object. The DRAGITEM structure contains the source object's rendering information, which is used to determine whether a Drop operation is valid at that point. Default information for the DRAGITEM structure is inserted by the default processing provided by the parent class, but an object class may override the method and include its own class-specific processing. The DRAGITEM structure is nested within a DRAGINFO structure, which is passed to any object over which the current item is being dragged. In a situation where more than one object is being dragged, a separate DRAGITEM is produced for each object and the set of structures is combined into a single DRAGINFO structure. The DRAGINFO structure, as shown in the following code fragments contains information about the Drag operation: typedef struct _DRAGINFO { ULONG cbDraginfo; /* Size of DRAGINFO */ USHORT cbDragitem; /* Size of DRAGITEM */ USHORT usOperation; /* Current Drag operation */ HWND hwndSource; /* Window handle of source */ SHORT xDrop; /* X coordinate of drop position */ SHORT yDrop; /* Y coordinate of drop position */ USHORT cditem; /* Count of DRAGITEM */ USHORT usReserved; /* Reserved for future use */ } DRAGINFO; The DRAGITEM data structure, as shown in the following code fragments is used to describe the items being dragged: typedef struct _DRAGITEM { HWND hwndItem; /* Conversation partner */ ULONG ulItemID; /* Identifies item being dragged */ HSTR hstrType; /* Type of item */ HSTR hstrRMF; /* Rendering mechanism and format*/ HSTR hstrContainerName; /* Name of source container */ HSTR hstrSourceName; /* Name of item at source */ HSTR hstrTargetName; /* Suggested name of item at dest*/ SHORT cxOffset; /* X offset of the origin of the */ /* image from the mouse hotspot */ SHORT cyOffset; /* Y offset of the origin of the */ /* image from the mouse hotspot */ USHORT fsControl; /* Source item control flags */ USHORT fsSupportedOps; /* Ops supported by source */ } DRAGITEM; The Workplace Shell itself performs the intialization of the DRAGINFO structure. If class-specific processing is required, the object may perform its own initialization during processing of wpFormatDragItem. A Workplace Shell object does not need to allocate the DRAGITEM structure, since it is allocated by the Workplace Shell, and a pointer is passed to wpFormatDragItem. The following sample code shows an example of how to use wpFormatDragItem: /* * Specify a unique RMF that will only be understood * by my instances of class MYFOLDER. */ SOM_Scope BOOL SOMLINK myf_wpFormatDragItem(MYFILE *somSelf, PDRAGITEM pdrgItem) { /* MYFILEData *somThis = MYFILEGetData(somSelf); */ MYFILEMethodDebug("MYFILE","myf_wpFormatDragItem"); parent_wpFormatDragItem(somSelf,pdrgItem); /* We do NOT want to really let the workplace shell render * our object, so change the rendering mechanism and format * to be uniquely ours. */ DrgDeleteStrHandle(pdrgItem->hstrRMF); pdrgItem->hstrRMF = DrgAddStrHandle(""); return(TRUE); } ═══ 12.2.2. Determining whether Data Can Be Exchanged ═══ During the drag portion of a Drag and Drop operation, the target must determine if it can exchange or receive data from the source for each object involved in the operation. The target determines which rendering mechanism and format to use. There are four combinations of rendering mechanisms and formats supported by the Workplace Shell: o o o o (DRM_OS2FILE, DRM_PRINT) X (DRF_TEXT) The DRAGITEM structure contains the source object's rendering information, which is used to determine whether a Drop operation is valid at that point. The pDragItemhstrRMF field in the DRAGITEM data structure is used to hold a handle to a string containing the rendering mechanism and format. ═══ 12.2.2.1. DRM_OBJECT ═══ The Workplace Shell interface uses the rendering mechanism of to communicate information about the Workplace Shell objects involved in a direct manipulation. For the rendering mechanism, pDragInfohwndSource is expected to be the window handle of the container holding objects which were inserted with wpCnrInsertObject. When you are using the DRM_OBJECT rendering mechanism, pDragItemulItemID indicates the object being dragged. For each item being dragged, pDragItemulItemID is the PMINIRECORDCORE or PRECORDCORE pointer associated with the object. The object can be retrieved using OBJECT_FROM_PREC on pDragItemulItemID. As soon as the target object has completed processing, a DM_ENDCONVERSATION message is sent to the window handle in pDragItemhwndItem. Note: There is no way to force source rendering for DRM_OBJECT. ═══ 12.2.2.2. DRM_OS2FILE ═══ This rendering mechanism can be used by various containers, including file folders and trash cans. These containers allow objects to be dragged and dropped on white space in the container to accomplish a Move or Copy operation. They also can allow objects in the same or another container to be dragged and dropped on objects within the container to accomplish an operation. When you are using DRM_OS2FILE, pDragItemulItemID is not used. If the Workplace Shell is to do target rendering, *(pDragItemhstrContainerName) is specified. It is the name of the directory that contains the file or the directory being dragged. Leave this field NULL if you want the Workplace Shell to send DM_RENDER messages, that is, to do source rendering for this object. *(pDragItemhstrSourceName) is the file or directory name being dragged and must be specified. *(pDragItemhstrTarget) is the suggested name of the file or directory at the target. Note: If pDragItemhstrContainerName and pDragItemhstrSourceName are both specified, the Workplace Shell converts the item being dragged to an object and treats it like a DRM_OBJECT. ═══ 12.2.2.2.1. Messages ═══ The following messages are used by the DRM_OS2FILE: o DM_RENDER This message is sent by a target to a source, via wpRender, to request a rendering for an object. When this message is received, the source determines if it understands the rendering mechanism and format selected by the target for the object. It also confirms that it allows the operation selected by the user for that object. The source must respond to this message before proceeding with the rendering operation. o DM_RENDERCOMPLETE This message is posted by a source to a target, via wpRenderComplete, to notify the target that the rendering operation has been completed by the source, either successfully or unsuccessfully. The source can elect to let the target retry a successful or an unsuccessful operation. In this case, it should return to its state at the time of the drop for that object and indicate, in the message, that a retry is allowed. Support for this message by a source is optional. If this message is not supported, then: - The source must convey all necessary information to the target order to allow it to handle the rendering operation. - It must always indicate that native rendering is allowed when replying to a DM_RENDER message. o DM_ENDCONVERSATION This message is sent by a target to a source to notify the source that the rendering operation is complete and that the conversation is terminated. When this message is received, the entire Drop operation for the object is complete. The source can now release any resources it had allocated to the drop and rendering operations. When the reply is received, the target can release the resources it had allocated to the operation. ═══ 12.2.3. Dragging over Another Object ═══ When an object is dragged over another object, the system invokes wpDragOver in the object being dragged over. This method receives a DRAGINFO structure, which contains pointers to DRAGITEM structures and other information. The potential target object examines this information to determine the validity of a Drop operation, and if the drop is not valid, changes the pointing device to indicate a "do not drop" situation. The following sample code shows an example of how to use wpDragOver: /* * Rejects objects that are not file system objects from being dropped * on the Browse_O_matic. */ SOM_Scope MRESULT SOMLINK Browse_O_Maticwps_wpDragOver( Browse_O_Matic *somSelf, HWND hwndCnr, PDRAGINFO pdrgInfo) { MRESULT mResult; ULONG ulCount; ULONG ulNumberOfObjects; /* Browse_O_MaticData *somThis = Browse_O_MaticGetData(somSelf); */ Browse_O_MaticMethodDebug("Browse_O_Matic", "Browse_O_Maticwps_wpDragOver"); /* Don't call the parent. Initialize mResult to allow */ /* the drag over to proceed */ mResult = MRFROM2SHORT(DOR_DROP, DO_MOVE); /* Determine the number of objects dragged */ /* over the Browse-O-Matic */ ulNumberOfObjects = DrgQueryDragitemCount( pdrgInfo); /* Check all the objects */ for (ulCount=0; ulCount < ulNumberOfObjects && SHORT1FROMMR(mResult) != DOR_NEVERDROP; ulCount++) { /* It must be a file system type object */ if(DrgVerifyRMF(DrgQueryDragitemPtr(pdrgInfo, ulCount), "DRM_OS2FILE", NULL)) mResult = MRFROM2SHORT(DOR_DROP, SHORT2FROMMR(mResult)); else mResult = MRFROM2SHORT(DOR_NEVERDROP, SHORT2FROMMR(mResult)); } return(mResult); } ═══ 12.2.4. Ending a Drop Operation ═══ When a Drop operation occurs, the object being dropped upon is notified by the system, which invokes wpDrop. This method accepts the DRAGINFO structure and determines whether the information is sufficient to take action, or whether further conversation is necessary to determine rendering information. ═══ 12.2.4.1. When Dropping on a Folder ═══ When dropping DRM_OBJECT or DRM_OS2FILE on a folder, with pDragItemhstrContainerName or pDragItemhstrSourceName defined, the Workplace Shell will perform the action, for example, Copy, Move, Shadow, and notify the source with a DM_ENDCONVERSATION message. When dropping DRM_OS2FILE on a folder, with pDragItemhstrContainerName set to NULL, the Workplace Shell will initiate source rendering by sending a DM_RENDERPREPARE message, if DC_PREPARE is specified in the pDragItemfsControl word in the DRAGITEM structure. It then sends a DM_RENDER message. Again, DM_ENDCONVERSATION is sent as previously described. ═══ 12.2.4.2. When Dropping on a Printer ═══ Workplace Shell implements the standard PM Print rendering mechanism, DRM_PRINT. When dropping DRM_OBJECT or DRM_OS2FILE on a printer, with pDragItemhstrContainerName or pDragItemhstrSourceName defined, the Workplace Shell will perform the action, and notify the source with a DM_ENDCONVERSATION message. When dropping DRM_OS2FILE, with pDragItemhstrContainerNameset to NULL, or dropping DRM_PRINT on a printer, the printer sends a DM_PRINTOBJECT message. ═══ 12.2.4.3. When Dropping on the Shredder ═══ The Workplace Shell shredder object supports a rendering mechanism called DRM_DISCARD, not a standard PM mechanism. When dropping DRM_OBJECT or DRM_OS2FILE on a shredder, with pDragItemhstrContainerName or pDragItemhstrSourceName defined, the Workplace Shell will perform the action, and notify the source with a DM_ENDCONVERSATION message. When dropping DRM_OS2FILE, with pDragItemhstrContainerName set to NULL, or dropping DRM_DISCARD on the shredder, the shredder sends a DM_DISCARDOBJECT message. The following sample code shows an example of how to use wpDrop: /* * Rejects objects that are not file system objects from being dropped * from being dropped on the Browse_O_matic. */ SOM_Scope MRESULT SOMLINK Browse_O_Maticwps_wpDrop( Browse_O_Matic *somSelf, HWND hwndCnr, PDRAGINFO pdrgInfo, PDRAGITEM pdrgItem) { CHAR pszBuffer[255]; MRESULT mResult; /* Browse_O_MaticData *somThis = Browse_O_MaticGetData(somSelf); */ Browse_O_MaticMethodDebug("Browse_O_Matic", "Browse_O_Maticwps_wpDrop"); mResult = MRFROM2SHORT(DOR_DROP, 0); /* Don't call the parent. Initialize mResult to allow */ /* the drop to proceed. */ if(DOR_NEVERDROP != SHORT1FROMMR(mResult) && DrgVerifyRMF(pdrgItem, "DRM_OS2FILE", NULL)) { /* Get the path */ DrgQueryStrName(pdrgItem->hstrContainerName, sizeof(pszBuffer), pszBuffer); /* Append the name of the object to the path */ DrgQueryStrName(pdrgItem->hstrSourceName, sizeof(pszBuffer) - strlen(pszBuffer), &pszBuffer[strlen(pszBuffer)]); _wpViewObject(somSelf, NULLHANDLE, OPEN_DEFAULT, (ULONG)pszBuffer); mResult = MRFROM2SHORT(DOR_DROP, SHORT2FROMMR(mResult)); } else mResult = MRFROMSHORT(DOR_NEVERDROP); return(mResult); } ═══ 13. Object Persistence: Save/Restore Methods ═══ The WPObject class provides methods that support persistent objects, that is, objects for which the system saves information. These methods include save and corresponding restore methods. This chapter provides information for using these state methods in Workplace Shell applications. ═══ 13.1. About Save/Restore Methods ═══ A Workplace Shell object can exist in two states: o Dormant: persistent form of object when it is stored away on disk. If the object's class is a descendant of WPFileSystem, its data is stored in the object's extended attributes. If it is a descendant of WPAbstract, its data is stored in the .INI file. o Awakened: object is instantiated as a SOM object that can have methods invoked upon it. The wpSaveState method will save the value of certain instance variables to a persistent storage location. The wpRestoreState method will restore these values for a newly awakened object. The Workplace Shell uses these methods to maintain important instance data for each object. If you write a subclass of a Workplace Shell class that includes its own new instance data, you must override these methods to ensure that the new instance data values are saved/restored along with the rest of the object's data. The following events trigger the Save/Restore methods: o Workplace Shell calls wpRestoreState when an object is awakened. o The wpSaveImmediate method calls wpSaveState to save its data to disk. o An application must save an object to disk when a critical instance variable is changed. The wpSaveImmediate method performs the save on the Workplace User-interface thread, and is therefore a synchronous operation. The wpSaveDeferred method causes the save to take place on a separate thread, asynchronously. Therefore, for performance reasons, wpSaveDeferred should be used in preference to wpSaveImmediate. o Workplace Shell calls wpSaveDeferred to asynchronously save the object's state when: - An object is closed - An object is made dormant - The system is shut down. The following figure shows the life cycle of an object: If you are implementing a subclass of a Workplace Shell class with its own instance variables that are supposed to persist, override wpSaveState and wpRestoreState. In the override for wpSaveState, call wpSaveData, wpSaveLong, or wpSaveString, for each piece of data you want saved, depending on the type of each piece of instance data associated with the object. Likewise, the override for wpRestoreState should call wpRestoreData, wpRestoreLong, or wpRestoreString, for each piece of data to be restored. The wpSaveState and wpRestoreState methods use a key to identify each piece of data for an object. This key is made up of the class name and a unique ULONG. Together, this key should uniquely identify a given piece of data for the object. For user-defined subclass instance data, assign a ULONG to each piece of data. Supply that ULONG along with your class name to wpSaveData, wpSaveLong, or wpSaveString, when saving that piece of data. Likewise, supply that ULONG along with your class name to wpRestoreData, wpRestoreLong, or wpRestoreString, when restoring that piece of data. ═══ 13.2. Using Save/Restore Methods ═══ The following sample codes (IDL and C files) serves as an example of how to use the Save/Restore methods. In this example, class X, a subclass of WPDataFile, introduces two pieces of persistent instance data. include wpdataf.idl interface X : WPDataFile { . . . implementation { ULONG ulA; //# Persistent instance data introduced by class X PSZ pszB; wpSaveState: override; //# To save your data wpRestoreState: override; //# To restore your data wpInitData: override; //# To supply default values for your data }; }; The following sample code shows the source code for X: BOOL SOMLINK x_wpSaveState(X * somSelf) { _wpSaveLong(somSelf, "X", 1, _ulA); _wpSaveString(somSelf, "X", 2, _pszB); // Key is X and 1 for _ulA return parent_wpSaveState(somSelf); // Key is X and 2 for _pszB } . . . BOOL SOMLINK x_wpRestoreState(X * somSelf, ULONG ulReserved) { ULONG ulSize; // Key is X and 1 for _ulA _wpRestoreLong(somSelf, "X", 1, &_ulA); // Key is X and 2 for _pszB _wpRestoreString(somSelf, "X", 2, &_pszB, &ulSize); return parent_wpRestoreState(somSelf, ulReserved); } . . . BOOL SOMLINK x_wpInitData(X * somSelf) { BOOL rc; rc = parent_wpInitData(somSelf); _ulA = 1001; _pszB = "hello"; return rc; } Note: Some of the save and restore methods are used in a complete program that is illustrated in Sample Code for Setup/Cleanup Methods. ═══ 14. Object Properties: Notebook Methods ═══ A notebook is a visual component used to display the setttings for an object and to enable the user to change them. This chapter describes the General and Window pages of the Settings notebook, and explains how to use the notebook methods in Workplace Shell applications. ═══ 14.1. About Notebook Methods ═══ WPObject defines a General page in the Settings notebook for all classes of objects. Because all Workplace Shell objects have general properties associated with them, therefore, all Workplace Shell objects have a General page in their Settings notebook. The General page describes all the general object properties such as the object's title, icon, and whether or not the object is a template. The title or icon of an object can be changed using the General page. For WPAbstract objects, the title and icon change is saved in the OS2.INI file. For the WPFileSystem objects, the title change is saved in the .LONGNAME extended attributes, and the icon change is saved in the .ICON extended attributes. WPObject also defines a Window page in the Settings notebook for all classes of objects. Most of the Abstract objects have both General and Window pages in the Settings notebook. Some Abstract objects like mouse and keyboard do not have a Window page because they have no open views other than Settings. Settings notebook pages for Workplace Shell objects are inherited from the ancestors of the Workplace Shell class. This means that they include pages that have been added or removed by their ancestor classes, in addition to the General and Window pages inherited from the root, WPObject class. For example, suppose that MyObject is a persistent object derived from the WPAbstract class. Because WPAbstract is derived from the WPObject class, MyObject inherits the characteristics and behaviors of WPAbstract and WPObject. WPAbstract inherits its Settings notebook from WPObject. MyObject, therefore, inherits WPObject's Settings notebook. Now suppose that MyObject class defines two additional pages in its Settings notebook, MyPage_1 and MyPage_2. This means that the Settings notebook for MyObject class has four pages: o General o Window o MyPage_1 o MyPage_2 Consider that YourObject class is derived from MyObject class. Therefore, by inheritance, YourObject class defines the following pages: o General o Window o MyPage_1 o MyPage_2 in its Settings notebook. YourObject class defines an additional page in its Settings notebook, YourPage. The Settings notebook for YourObject class has now five pages: General Inherited from the WPObject class. Window Inherited from the WPObject class. MyPage_1 Inherited from MyObject class. MyPage_2 Inherited from MyObject class. YourPage Defined by YourObject. The tabs in the Settings notebook for MyObject and YourObject are shown in the following figure: ┌───────────────────────┐ ┌───────────────────────┐ │ MyObject Settings │ │ YourObject Settings │ ├───────────────────────┤ ├───────────────────────┤ │ ├────────────┐ │ ├────────────┐ │ │ General │ │ │ General │ │ ├────────────┘ │ ├────────────┘ │ ├────────────┐ │ ├────────────┐ │ │ Window │ │ │ Window │ │ ├────────────┘ │ ├────────────┘ │ This Page Is not └────────────┐ │ This Page Is not ├────────────┐ │ Inherited from MyPage_1 │ │ Inherited from │ MyPage_1 │ │ MyObject's ┌────────────┘ │ YourObject's ├────────────┘ │ Ancestors. ├────────────┐ │ Ancestors. ├────────────┐ │ │ MyPage_2 │ │ │ MyPage_2 │ │ ├────────────┘ │ ├────────────┘ │ │ │ └────────────┐ │ │ │ YourPage │ │ │ │ ┌────────────┘ │ │ │ │ └───────────────────────┘ └───────────────────────┘ Every Settings notebook in the Workplace Shell should have Undo, Default, and Help push buttons. Any changes to the Settings notebook takes effect immediately, although sometimes the changes are delayed until the focus is changed. ═══ 14.2. Using Notebook Methods ═══ This section describes how the Settings notebook methods are used to add or to remove pages that a class has inherited from its ancestors' Settings notebook. ═══ 14.2.1. Inserting Notebook Pages ═══ An object's Settings notebook is created by the Workplace Shell by calling the object's wpAddSettingsPages. Adding pages to the Settings notebook that a class has inherited from its ancestors is accomplished by overriding wpAddSettingsPages and by calling a new method that inserts the page. The new method calls wpInsertSettingsPage to insert the page into the object's notebook. The following sample code shows how to insert pages to an object's notebook: /************************** New Method ****************************/ SOM_Scope ULONG SOMLINK MyObject_wpAddAnotherPage( MyObject *somSelf, HWND hwndNotebook) { PAGEINFO pageinfo; . . /* Setup the page information data structure for my new page */ . . /* Add the page to the Settings notebook */ return _wpInsertSettingsPage(somSelf, hwndNotebook, &pageinfo); } /************************ Method Overrides *************************/ SOM_Scope BOOL32 SOMLINK MyObject_wpAddSettingsPage ( MyObject *somSelf, HWND hwndNotebook) { . . if (parent_wpAddSettingsPage (somSelf, hwndNotebook) && _wpAddAnotherPage (somSelf, hwndNotebook)) return (TRUE); /* Page added successfully */ else return (FALSE); /* Something failed */ } New pages for an object's Settings notebook can be placed at the top or bottom of pages inherited from the object's ancestor classes. By calling parent_wpAddSettingsPages before calling the new wpAddAnotherPage, the new page is added to the top of the Settings notebook, above pages inherited from ancestor classes. If the sequence is reversed, the new page is added to the bottom of the Settings notebook, below pages inherited from ancestor classes. When a new page is added to the Settings notebook, any changes made to the object's instance data can be refreshed from the file system, via wpCnrRefreshDetails. This instance method causes all currently visible RECORDCORE structures to be refreshed with the current object details. ═══ 14.2.2. Removing Notebook Pages ═══ A page can be removed from an object's Settings notebook by overriding the ancestors' method that inserts it. The Settings notebook for YourObject class inherits the General, Window, MyPage_1, and MyPage_2 pages defined by its ancestors, MyObject and WPObject. YourObject class might have requirements for MyPage_1 but not MyPage_2. To remove MyPage_2 from YourObject's Settings notebook, YourObject must override the method inherited from MyObject that adds MyPage_2 to the Settings notebook, and return SETTINGS_PAGE_REMOVED without calling the parent method. The following sample code shows how to remove a page from an object's notebook: /********************* Method Overrides ****************************/ SOM_Scope ULONG SOMLINK YourObject_wpAddAnotherPage( YourObject *somSelf HWND hwndNotebook) { . . . /* Remove the page from the Settings notebook */ return (SETTINGS_PAGE_REMOVED); } The same technique can be used to replace or to remove the General page from an object's Settings notebook by overriding wpAddSettingsPages and wpAddObjectGeneralPage. The override to wpAddSettingsPages calls wpAddObjectGeneralPage. To remove the General page, the override to wpAddObjectGeneralPage returns SETTINGS_PAGE_REMOVED without calling the parent method. To replace the General page with another page, the override to wpAddObjectGeneralPage calls wpInsertSettingsPage without calling the parent method. ═══ 15. Object Usage: Usage Methods ═══ Every Workplace Shell object in the system has an in-use list. Object usage methods allow an object to keep track of its resources and how it is being used. This chapter provides information for using in-use lists that are associated with objects. ═══ 15.1. About Usage Methods ═══ The in-use list provides the object with information such as: o The number of container windows into which the object has been inserted (USAGE_RECORD) o The number of open views (contents and settings) of the object that already exist (USAGE_OPENVIEW) o How much memory the object has allocated (USAGE_MEMORY) o How many awakened shadows there are of the object (USAGE_LINK) o Which application opened the object (USAGE_OPENFILE). Note that this information only applies to data file objects. All objects that the user interacts with are actually just records that have been inserted into a container control. A container is an object, such as a folder, which also has an in-use list. Because of the close relationship between an object's in-use list and container objects, this chapter includes a description of methods that are relevant to container usage as well as object usage. Object Usage methods, as shown in the following table, allow an object to keep track of its resources and how it is being used: ┌─────────────────────────┬───────────────────────────────────┐ │Method Name │Description │ ├─────────────────────────┼───────────────────────────────────┤ │wpAddToObjUseList │Adds an object to the list of │ │ │objects in use by the object. │ ├─────────────────────────┼───────────────────────────────────┤ │wpCnrDeleteUseItem │Deletes the object's USAGE_RECORD │ │ │use-item for the specified │ │ │container. │ ├─────────────────────────┼───────────────────────────────────┤ │wpDeleteFromObjUseList │Deletes an object from the list of │ │ │objects in use by the object. │ ├─────────────────────────┼───────────────────────────────────┤ │wpFindUseItem │Retrieves an object from the list │ │ │of objects in use by the object. │ ├─────────────────────────┼───────────────────────────────────┤ │wpFindViewItem │Retrieves a USAGE_OPENVIEW item │ │ │from the list of items in use by │ │ │the object. │ ├─────────────────────────┼───────────────────────────────────┤ │wpIsLocked │Tells you whether the object is │ │ │locked or not. │ ├─────────────────────────┼───────────────────────────────────┤ │wpLockObject │Increases the lock counter for the │ │ │object. Objects that are locked │ │ │will not be made dormant. │ ├─────────────────────────┼───────────────────────────────────┤ │wpUnlockObject │Unlocks the object so that it can │ │ │be made dormant. │ └─────────────────────────┴───────────────────────────────────┘ The in-use list is a linked list of USEITEM data structures. It consists of an item type and a pointer to the next USEITEM data structure, immediately followed by an item type-specific data structure. The types of items that can be added to an object's in-use list and the type-specific data structures that follow each USEITEM data structure are shown in the following table: ┌───────────────┬──────────┬───────────────────────────────────┐ │Item │Structure │Description │ ├───────────────┼──────────┼───────────────────────────────────┤ │USAGE_LINK │LINKITEM │A shadow of the object has been │ │ │ │awakened. │ ├───────────────┼──────────┼───────────────────────────────────┤ │USAGE_MEMORY │MEMORYITEM│Memory has been allocated by │ │ │ │wpAllocMem. │ ├───────────────┼──────────┼───────────────────────────────────┤ │USAGE_OPENFILE │VIEWFILE │The object (if a data file) has │ │ │ │been opened. │ ├───────────────┼──────────┼───────────────────────────────────┤ │USAGE_OPENVIEW │VIEWITEM │A view of the object has been │ │ │ │opened. │ ├───────────────┼──────────┼───────────────────────────────────┤ │USAGE_RECORD │RECORDITEM│The object has been inserted into a│ │ │ │container window. │ └───────────────┴──────────┴───────────────────────────────────┘ ═══ 15.2. Using Usage Methods ═══ This section describes the different usage methods along with explaining how each of them relate to an in-use item. ═══ 15.2.1. Adding Items to the Object's In-Use List ═══ The wpAddToObjUseList method adds items to the object's in-use list. When an object's memory is allocated, wpAllocMem calls wpAddToObjUseList to add a USAGE_MEMORY item to the object's in-use list. The allocated memory immediately follows the MEMORYITEM data structure. The following figure shows the syntax of the MEMORYITEM data structure: typedef struct _MEMORYITEM { ULONG cbBuffer; /* Number of bytes in memory block */ }MEMORYITEM; The wpOpen method calls wpAddToObjUseList to add a USAGE_OPENVIEW item to the object's in-use list. The wpSwitchTo method scans the in-use list for USAGE_OPENVIEW items to give focus to an already existing view. In general, wpViewObject is used instead of wpOpen because wpViewObject considers the setting in the Object open behavior group-box control on the Window page of the Settings notebook, and calls either wpOpen or wpSwitchTo. The following figure shows the syntax of the VIEWITEM data structure: typedef struct _VIEWITEM { ULONG view; /* Object view that this represents */ LHANDLE handle; /* Open handle */ ULONG ulViewState; /* View state flags */ HWND hwndCnr; /* Used only by system */ PMINIRECORDCORE pRecord; /* Used only by system */ }VIEWITEM; When wpSetLinkToObject is called to link a shadow to the object it points to, wpAddToObjUseList is called to add the USAGE_LINK item to the original object's in-use list. The following figure shows the syntax of the LINKITEM data structure: typedef struct _LINKITEM { WPObject *LinkObj; /* The link object */ }LINKITEM; When a data file is opened, its associated program is started and a USAGE_OPENFILE use-item is added to the data file's in-use list. The following figure shows the syntax of the VIEWFILE data structure: typedef struct _VIEWFILE { ULONG ulMenuId; /* Menu id if association or menu page */ LHANDLE handle; /* Open handle */ HWND hwndCnr; /* Used only by system */ PMINIRECORDCORE pRecord; /* Used only by system */ }VIEWFILE; ═══ 15.2.2. Removing Items from the Object's In-Use List ═══ When wpCnrInsertObject puts an object into a container window, its adds a USAGE_RECORD item to the object's in-use list. Conversely, when wpCnrRemoveObject is called, the USAGE_RECORD item is deleted from the object's in-use list and the object is removed from the container. The following figure shows the syntax of the RECORDITEM data structure: typedef struct _RECORDITEM { HWND hwndCnr; /* Container into which object */ /* is being inserted */ PMINIRECORDCORE pRecord; /* Record pointer within container */ ULONG ulUser; /* For application use */ }RECORDITEM; Likewise, when wpFreeMem is called to free memory, it calls wpDeleteFromObjUseList to delete a USAGE_MEMORY item from the object's in-use list. When views are closed by the object's wpClose, wpDeleteFromObjUseList removes the applicable USAGE_OPENVIEW item from the object's in-use list. The wpCnrDeleteUseItem method deletes the USAGE_RECORD use-item for the specified container, but does not remove the object from the container. Use wpCnrRemoveObject to delete the USAGE_RECORD use-item and also to remove the object from the container. ═══ 15.2.3. Increasing or Decreasing the Object's Lock Count ═══ The wpLockObject method increases the object's lock count by one. The wpUnlockObject method decreases the object's lock count by one. If the lock count is zero, the object can be made dormant. The wpIsLocked method returns TRUE if the object is locked. Otherwise, it returns FALSE. ═══ 15.2.4. Finding an Object's In-Use Item ═══ You can use wpFindUseItem to determine how an object is being used. It searches an object's in-use list for items of a specified type and returns a pointer to the USEITEM data structure that matches that specified type. The wpFindViewItem method finds USAGE_OPENVIEW items in the use list. The following figure shows the syntax of the USEITEM data structure: typedef struct _USEITEM { ULONG type; /* Type of this item */ struct _USEITEM FAR *pNext; /* Next item in use list */ }USEITEM; The following sample code shows an example of how you can use the usage methods. It uses the wpFindUseItem and wpFindViewItem along with the USAGE_OPENVIEW item. SOMAny *Object; PVIEWITEM pViewItem; PUSEITEM pUseFile; ULONG ulView; // Are there any open views of this object? if (_wpFindUseItem(Object, USAGE_OPENVIEW, NULL)) { // Find any views of this object for (pViewItem = _wpFindViewItem(Object, VIEW_ANY, NULL); pViewItem; pViewItem = _wpFindViewItem(Object, VIEW_ANY, pViewItem)) { // Is a program running? if (pViewItem->view == OPEN_RUNNING) { ulView = (ULONG)0; // Find any open file use-items for (pUseFile = _wpFindUseItem(Object, USAGE_OPENFILE, NULL); pUseFile; pUseFile = _wpFindUseItem(Object, USAGE_OPENFILE, pUseFile)) { // Does the VIEWFILE's open handle match the VIEWITEM's open handle? if (((PVIEWFILE)(pUseFile+1))->handle == pViewItem->handle) { // Save the VIEWFILE's menu id ulView = ((PVIEWFILE)(pUseFile+1))->ulMenuId; break; } } } } } ═══ 16. Object User Action: Pop-Up Menu Methods ═══ This chapter describes the pop-up context menus that can be used to invoke actions on Workplace Shell objects. It also provides an overview of how to create and manipulate the pop-up context menu for your Workplace Shell objects. ═══ 16.1. About Pop-Up Menu Methods ═══ Pop-up menu methods support the actions that the user can perform on an object. These actions appear in a context or pop-up menu when the user presses button 2 of the pointing device. A pop-up menu contains action choices for an object in its current context or state. The contents of a pop-up menu depends on the state of the object. Pop-up menus consist of a set of selectable items and any pull-down or conditional cascaded menus associated with them. In the following figure, Open, Settings, Open parent, Refresh now, and so on, are items in the object's primary pop-up menu. Icon, Tree, and Details are items in the Open pull-down or conditional cascaded menu. Conditional cascaded menus have mini-push buttons displayed next to the pop-up menu item. When the user selects the mini-push button, the pull-down menu is displayed. As shown in the above figure, Open, Help, and Sort have mini-push buttons that are represented by a right arrow () surrounded by a square box. If the user selects one of these three pop-up menu items, a default action listed in the submenu is performed. The default action is represented by a check mark. The default action for the Open item is Icon view, the Help item is General help, and the Sort item is Name. This submenu is called a conditional cascaded menu because it is displayed only if the user selects the mini-push button. Like Settings notebook pages, pop-up menus are inherited from a class' ancestor classes. This means that they include pop-up menu items that ancestor classes have added to or removed from the pop-up menu inherited from WPObject. The pop-up methods permit you to add new menu items to or remove menu items from the pop-up menu inherited from an object's ancestor classes, as shown in the following table: ┌─────────────────────────┬───────────────────────────────────┐ │Method │Description │ ├─────────────────────────┼───────────────────────────────────┤ │wpFilterPopupMenu │Filters out options from the │ │ │object's pop-up menu that do not │ │ │apply. │ ├─────────────────────────┼───────────────────────────────────┤ │wpInsertPopupMenuItems │Inserts items into the object's │ │ │pop-up menu. │ ├─────────────────────────┼───────────────────────────────────┤ │wpModifyPopupMenu │Adds new options to the object's │ │ │pop-up menu. │ └─────────────────────────┴───────────────────────────────────┘ When the user requests an object's pop-up menu, the Workplace Shell builds it by calling the object's wpFilterPopupMenu and wpModifyPopupMenu. The wpInsertPopupMenuItems method is called by an override to wpModifyPopupMenu to add new options to an object's pop-up menu. ═══ 16.1.1. Support for User Selection of Standard Pop-Up Menu Items ═══ When the user selects a standard action from a pop-up menu, the Workplace Shell calls one of the pop-up menu methods shown in the following table: ┌────────────────────┬────────────────────────────────────────┐ │Method Name │Description │ ├────────────────────┼────────────────────────────────────────┤ │wpClose │Closes all open views of an object. │ ├────────────────────┼────────────────────────────────────────┤ │wpCopyObject │Creates a new copy of the object. │ ├────────────────────┼────────────────────────────────────────┤ │wpCreateFromTemplate│Creates an object from a template. │ ├────────────────────┼────────────────────────────────────────┤ │wpCreateShadowObject│Creates a shadow of an object. │ ├────────────────────┼────────────────────────────────────────┤ │wpDelete │Deletes an object and prompts for │ │ │confirmation, if necessary. │ ├────────────────────┼────────────────────────────────────────┤ │wpDisplayHelp │Displays a help panel. │ ├────────────────────┼────────────────────────────────────────┤ │wpHide │Hides or minimizes open views of an │ │ │object. │ ├────────────────────┼────────────────────────────────────────┤ │wpMoveObject │Moves the object to a different │ │ │location. │ ├────────────────────┼────────────────────────────────────────┤ │wpOpen │Opens a view of the object. │ ├────────────────────┼────────────────────────────────────────┤ │wpPrintObject │Prints a view of the object. │ ├────────────────────┼────────────────────────────────────────┤ │wpRestore │Restores hidden or minimized views of an│ │ │object. │ └────────────────────┴────────────────────────────────────────┘ ═══ 16.1.2. Open Views ═══ Objects can have open actions or open views associated with them. Open views typically are the views of an object, for example, Icon, Tree, Details, and Settings. Open views, for data file objects, also include programs or program references that the user has associated with the object. Open views are displayed when the user selects the cascaded mini-push button that appears next to the Open action on the pop-up menu. The user then can select the default open view or any of the open views listed in the conditional cascaded menu. The Workplace Shell defines a set of predefined open views, as shown in the following table: ┌────────────────────┬────────────────────────────────────────┐ │View │Description │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_CONTENTS │Opens content view. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_DEFAULT │Opens default view. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_DETAILS │Opens Details view. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_HELP │Opens help view. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_RUNNING │Executes object. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_SETTINGS │Opens Settings notebook. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_TREE │Opens Tree view. │ ├────────────────────┼────────────────────────────────────────┤ │OPEN_USER │Opens class-specific view (value greater│ │ │than OPEN_USER) │ └────────────────────┴────────────────────────────────────────┘ Some of the predefined open views are meaningful only to certain Workplace Shell classes: o OPEN_RUNNING is meaningful only to a program or program reference object o OPEN_TREE is meaningful only to file system objects such as folders, drives and directories. Workplace Shell classes can define new open views for their objects by: 1. Adding the New view menu item to the Open submenu. 2. Overriding wpMenuItemSelected to support user selection of the New view menu item. 3. Overriding wpOpen to open the New view. 4. Creating and opening a standard window for the New view by calling WinCreateStdWindow. Note: The preferred method for displaying application views of an object is for the object to start a separate process, using DosExecPgm, for the application. This approach moves the larger part of the application code out of the Workplace Shell's process, thus conserving the its resources. It also helps prevent a misbehaved application from potentially interfering with the execution of the Workplace Shell. 5. Adding a USAGE_VIEW item to the object's in-use list by calling wpAddToObjUseList. 6. Registering the New view by calling wpRegisterView. Note: The Sample Code for Pop-Up Menu Methods is a complete program that demonstrates how to define and open a new open view. ═══ 16.2. Using Pop-Up Menu Methods ═══ This section describes the following: o Adding and removing standard pop-up menu items o Adding and removing items to a pop-up menu inherited from an object's ancestors o Adding conditional cascaded menus to a pop-up menu o Supporing user selection of new pop-up menu items. Note: A complete program is provided to demonstrate how to customize a Workplace Shell pop-up menu. The program is illustrated in Sample Code for Pop-Up Menu Methods. ═══ 16.2.1. Adding and Removing Standard Pop-Up Menu Items ═══ The pop-up menu of a Workplace Shell object consists of a subset of the standard pop-up menu items and any new menu items defined for the object's class or inherited from other ancestors. The WPObject class defines a set of standard pop-up menu items that are inherited by all Workplace Shell objects. The WPDesktop, WPFolder, WPPalette, and WPProgram Workplace Shell classes define standard pop-up menu items for their descendants. Each standard pop-up menu item is associated with a flag, as shown in the following table: ┌────────────────────┬────────────────────┬────────────────────┐ │Class │Item Flag │Description │ ├────────────────────┼────────────────────┼────────────────────┤ │WPDesktop │CTXT_LOCKUP │Open Lockup now │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SHUTDOWN │Open Shut down │ ├────────────────────┼────────────────────┼────────────────────┤ │WPFolder │CTXT_ARRANGE │Open Arrange │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_DETAILS │Open Details view │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_FIND │Open Find dialog │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_ICON │Open Icon view │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SELECT │Open Select │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SORT │Open Sort dialog │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_TREE │Open Tree view │ ├────────────────────┼────────────────────┼────────────────────┤ │WPObject │CTXT_ARRANGE │Open Arrange │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_CLOSE │Close │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_COPY │Copy │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_CRANOTHER │Create another │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_DELETE │Delete │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_DETAILS │Open Details view │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_HELP │Help │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_ICON │Open Icon view │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_LINK │Create shadow │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_LOCKUP │Open Lockup dialog │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_MOVE │Move │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_NEW │Create another │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_OPEN │Open │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_PALETTE │Open Palette │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_PICKUP │Pick up an object │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_PRINT │Print │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_PROGRAM │Open program │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_PUTDOWN │Put an object down │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_REFRESH │Refresh │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SELECT │Open Select │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SETTINGS │Open Settings │ │ │ │notebook │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SHADOW │Create shadow │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SHUTDOWN │Open Shut down │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SORT │Open Sort dialog │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_SWITCHTO │Switch to │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_TREE │Open Tree view │ ├────────────────────┼────────────────────┼────────────────────┤ │ │CTXT_WINDOW │Window │ ├────────────────────┼────────────────────┼────────────────────┤ │WPPalette │CTXT_PALETTE │Open palette │ ├────────────────────┼────────────────────┼────────────────────┤ │WPProgram │CTXT_PROGRAM │Open program │ └────────────────────┴────────────────────┴────────────────────┘ Workplace Shell classes can add or delete standard pop-up menu items from their pop-up menu by overriding wpFilterPopupMenu. The wpFilterPopupMenu method returns the flags that represent the standard pop-up menu items for the object. By removing a standard menu item from the pop-up menu, the override to wpFilterPopupMenu masks the flag that corresponds to the item being removed from the flags that represent the standard pop-up menu items inherited from the object's parent. For example, suppose that printing MyObject has no meaning. To remove the Print option from MyObject's pop-up menu, wpFilterPopupMenu is overridden as shown in the following figure: /************************* Method Overrides ****************************/ /* Filters out any options from the pop-up menu that don't apply */ SOM_Scope ULONG SOMLINK MyObject_wpFilterPopupMenu (MyObject *somSelf,ULONG ulFlags, HWND hwndCnr, BOOL32 fMultiSelect) { MyObjectData *somThis = MyObjectGetData(somSelf); MyObjectMethodDebug("MyObject","MyObject_wpFilterPopupMenu"); /* Don't allow anyone to print MyObject */ return(parent_wpFilterPopupMenu(somSelf,ulFlags,hwndCnr,fMultiSelect) & ~CTXT_PRINT); } The flags that represent the standard pop-up menu items of MyObject's parent class are returned from the call to parent_wpFilterPopupMenu. To remove the Print option from MyObject's pop-up menu, these flags are joined to the complement of CTXT_PRINT using the AND logical operand. Conversely, if the pop-up menu of MyObject's parent class did not include the Print option, the Print option can be added to MyObject's pop-up menu by joining these flags to CTXT_PRINT using the OR logical operand. Note: An object's pop-up menu is inherited from its ancestors. To ensure that calls to wpFilterPopupMenu belonging to the object's ancestors do not add the menu item after it is deleted, or remove the menu item after it is added, the parent_wpFilterPopupMenu is called first. ═══ 16.2.2. Adding and Removing Class Items to a Pop-Up Menu ═══ New items are added to the pop-up menu inherited from an object's ancestors by overriding the object's wpModifyPopupMenu and calling wpInsertPopupMenuItems. For example, to add New item to MyObject's pop-up menu, the new menu item is defined in a resource file in the same manner as menus are defined in PM programs. An ID is assigned to the new menu and to the menu item, as shown in the following sample code: #define ID_MOREITEMS WPMENUID_USER+1 #define ID_NEWITEMS WPMENUID_USER+2 MENU ID_MOREITEMS LOADONCALL MOVEABLE DISCARDABLE BEGIN MENUITEM "New Item", ID_NEWITEMS END Menu items can also be deleted by overriding wpModifyPopupMenu and by sending the MM_DELETEITEM message to the menu. IDs for class-specific menus and menu items have a value greater than WPMENUID_USER, so they do not conflict with IDs for menus and menu items defined by the Workplace Shell classes, as shown in the following sample code: /* Add a new item to MyObject's pop-up menu */ SOM_Scope BOOL32 SOMLINK MyObject_wpModifyPopupMenu (MyObject *somSelf,HWND hwndMenu, HWND hwndCnr, ULONG ulPosition) /* Remove an item from MyObject's pop-up menu */ WinSendMsg(hwndMenu, MM_DELETEITEM, MPFROM2SHORT(MY_ITEMID,FALSE), NULL); { /* Insert new items in MyObject's primary menu */ _wpInsertPopupMenuItemsA(somSelf, hwndMenu, ulPosition, hmod, ID_MOREITEMS, WPMENUID_PRIMARY); /* Add the items inherited from MyObject's parent */ return (parent_wpModifyPopupMenu(somSelf, hwndMenu, hwndCnr, ulPosition)); } The wpInsertPopupMenuItems method requires: o A handle to the module where the menu resource is defined o The ID for the menu resource o The ID for the menu where the item is being inserted. In the above sample code, ID_MOREITEMS is the ID for the menu resource that defines the new menu item being added to the object's primary pop-up menu. WPMENUID_PRIMARY is the ID for the object's primary pop-up menu, where New item is being inserted. An item can be added to a pop-up submenu or conditional cascaded menu by specifying the ID for the conditional cascaded menu on the call to wpInsertPopupMenuItems. For example, to add New item to the Open conditional cascaded menu, the call to wpInsertPopupMenuItems is modified as shown in the following sample code: /* Insert new items in MyObject's Open submenu */ _wpInsertPopupMenuItemsA(somSelf, hwndMenu, ulPosition, hmod, ID_MOREITEMS, WPMENUID_OPEN); ═══ 16.2.3. Adding Conditional Cascaded Menus to a Pop-Up Menu ═══ Items on an object's pop-up menu sometimes have pull-down menus or submenus associated with them. In the previous sample codes, New item is not a pull-down menu. However, New item can be defined as a pull-down menu by defining it as a submenu in MyObject's resource file, as shown in the following sample code: #define ID_MOREITEMS WPMENUID_USER+1 #define ID_NEWITEMS WPMENUID_USER+2 #define ID_SUBITEM1 WPMENUID_USER+3 #define ID_SUBITEM2 WPMENUID_USER+4 #define ID_SUBITEM3 WPMENUID_USER+5 MENU ID_MOREITEMS LOADONCALL MOVEABLE DISCARDABLE BEGIN SUBMENU "New Item", ID_NEWITEMS BEGIN MENUITEM "SubItem_1" ID_SUBITEM1 MENUITEM "SubItem_2" ID_SUBITEM2 MENUITEM "SubItem_3" ID_SUBITEM3 END END The New item submenu is added to MyObject's primary pop-up menu using the same technique as shown in the "Adding Items to Pop-Up Menu Inherited from an Object's Ancestors" section. For the Workplace Shell to display the submenu as a conditional cascaded menu with the mini-push button and default selection, the menu's style and default selection must be set, as shown in the following sample code: /********************** Method Override ******************************/ /* Add a new item to MyObject's pop-up menu */ SOM_SCOPE BOOL32 SOMLINK MyObject_wpModifyPopupMenu (MyObject *somSelf, HWND hwndMenu, HWND hwndCnr, ULONG iPosition) { . . MENUITEM mi; . . /* Get a handle to the New item submenu */ WinSendMsg(hwndMenu, MM_QUERYITEM, MPFROM2SHORT(ID_NEWITEMS), (MPARAM)&mi); hwndSubMenu = mi.hwndSubMenu; /* Query the menu's style */ ulstyle = WinQueryWindowULong(hwndSubMenu, QWL_STYLE); /* Add conditional cascaded capabilities to the existing menu style */ ulstyle |= MS_CONDITIONALCASCADE; /* Set the menu style to include conditional cascaded capabilities */ WinSetWindowULong(hwndSubMenu, QWL_STYLE, ulstyle); /* Set the default selection in the submenu. It must exist. */ WinSendMsg(hwndSubMenu, MM_SETDEFAULTITEMID, (MPARAM)ID_SUBITEM1, 0L); . . } ═══ 16.2.4. Supporting User Selection of New Pop-Up Menu Items ═══ When a class defines new actions for its pop-up menu, it must provide for the processing of the actions when the user selects the action. This is done by overriding the following pop-up menu methods: ┌─────────────────────────┬───────────────────────────────────┐ │Method │Description │ ├─────────────────────────┼───────────────────────────────────┤ │wpMenuItemHelpSelected │Displays the help associated with │ │ │class-specific pop-up menu item. │ ├─────────────────────────┼───────────────────────────────────┤ │wpMenuItemSelected │Processes class-specific pop-up │ │ │menu item. │ └─────────────────────────┴───────────────────────────────────┘ Using the previous sample code, MyObject supports SubItem_1 by overriding wpMenuItemSelected, as shown in the following sample code: /******************** Method Override ********************************/ /* Process input from the extra menu option that we added */ SOM_Scope void SOMLINK MyObject_wpMenuItemSelected (MyObject *self, HWND hwndFrame, ULONG MenuID) { . . /* Which of our menu items was selected? */ switch( MenuId ) { case ID_SUBITEM1: . . case ID_SUBITEM2: . . case ID_SUBITEM3: . . case ID_SUBITEM4: . . default: parent_wpMenuItemSelected } } MyObject can support help for new pop-up menu items by overriding wpMenuItemHelpSelected in a similar manner. These help methods are explained in Object Aid: Help Methods. ═══ 16.3. Sample Code for Pop-Up Menu Methods ═══ This section illustrates a complete pop-up menu sample program. The source code for a sample Hello application is provided here to demonstrate how to customize a Workplace Shell pop-up menu. The application creates a new class, Hello, from the WPDataFile class with a modified pop-up menu, and then creates an instance of the new class called MyHello. An instance of the Hello class will be just like a WPDataFile object with the following exceptions: o The Open submenu will have a Say Hello item. MyHello's primary menu will have a Message Box item. The context menu will have the Move item removed. The following figure shows MyHello object and its pop-up menu: o Selecting the Open Say Hello item or double clicking on the object will cause a window to display the text "Hello, Workplace Shell.", as shown in the following figure: o Double clicking on the Message Box item will display a message box with information about this example, as shown in the following figure: ═══ 16.3.1. Pop-Up Menu Application Sample Code ═══ The pop-up menu application includes the following files: File Name Description HELLO.IDL Class interface definition HELLO.C Source code HELLO.RC Resource code HELLO.MAK Hello make file for building the application Following these files are three REXX files that register and deregister the new class with the Workplace Shell, and create an instance of the class. ═══ 16.3.1.1. Class Definition File for Hello ═══ The following sample illustrates the class interface definition file (IDL): //# Include the class definition file for the parent classes #include #include interface M_Hello; // Forward reference to metaclass //#****************************************************************************** //# Define the new class //#****************************************************************************** interface Hello : WPDataFile { // // CLASS: Hello // // CLASS HIERARCHY: // // SOMObject // └───WPObject // └───WPFileSystem // └───WPDataFile // └───Hello // // DESCRIPTION: // // This is the sample class to demonstrate Workplace Shell menu // customization. // #ifdef __SOMIDL__ implementation { //# Class modifiers externalstem = hello; local; externalprefix = hlo_; majorversion = 1; minorversion = 2; filestem = hello; metaclass = M_Hello; callstyle = idl; dllname = "hello.dll"; passthru C_h = "" "#define INCL_WIN" "#include " "" "/*" " * The following user-defined pop-up menu items (ID_xxx) should" " * be higher than WPMENUID_USER." " *" " * The ID_OPENHELLO will become a submenu of the system's pop-up" " * open menu id, WPMENUID_OPEN." " */" "" "#define ID_OPENHELLO (WPMENUID_USER+1) /* Menus to be added */" "#define ID_MSGBOX (WPMENUID_USER+2)" "#define IDM_OPENHELLO (WPMENUID_USER+3) /* Submenus of added menus */" "#define IDM_MSGBOX (WPMENUID_USER+4)" "#define ID_FRAME 3000 /* Hello window frame ID */" "" "// The ID of the Hello window view. This is returned by the override" "// of wpclsQueryDefaultView to specify that the default view" "// is to open the Hello window. This ID MUST be the same as the ID of" "// the open menu item." "" "#define OPEN_HELLO ID_OPENHELLO"; //#****************************************************************************** //# Define overridden methods //#****************************************************************************** wpFilterPopupMenu: override; // METHOD: wpFilterPopupMenu // // DESCRIPTION: Remove any menu items from the context // menu that don't apply. // // HOW TO OVERRIDE: No restrictions. // // NOTES: // // This method is called when an objects' context menu has been requested // (i.e. right click or S-F10 on an object) before displaying the menu. It // is called before wpModifyPopupMenu. wpModifyPopupMenu: override; // METHOD: wpModifyPopupMenu // // DESCRIPTION: Add the menu items to the context menu. // // NOTES: // // This method is called when an objects' context menu has been requested // (i.e. right click or S-F10 on an object) before displaying the menu. It // is called after wpFilterPopupMenu. wpMenuItemSelected: override; // METHOD: wpMenuItemSelected // // DESCRIPTION: Processes input from the menu options that was added. // // NOTES: // // This method is called when an item in an objects' context menu has been // selected. wpOpen: override; // METHOD: wpOpen // // DESCRIPTION: Opens the Hello Workplace Shell window. // // NOTES: // // This method is called when a new open view of an object is needed, // i.e. when an item in an object's Open submenu has been selected or // when an object is double clicked on. This is equivalent to selecting // the default item in the object's Open submenu. // // wpOpen should always open a new view. The Workplace Shell actually calls // wpViewObject first when an object is double clicked on or an open // submenu item is selected. wpViewObject will then call wpOpen if there // is currently no open view of the selected Open submenu item or if // mutliple concurrent views of the object are enabled. }; /* End implementation */ #Endif /* __SOMIDL__ */ }; //#****************************************************************************** //# Define the metaclass //#****************************************************************************** interface M_Hello: M_WPDataFile { //#****************************************************************************** //# Define metaclass methods //#****************************************************************************** HMODULE clsQueryModuleHandle(); // METHOD: clsQueryModuleHandle // // DESCRIPTION: // // Returns the module handle of this class. If this is the // first invocation, DosQueryModuleHandle is called to save the handle // for future invocations. // // RETURN: // // 0 Unsuccessful // non-zero Module handle // // NOTES: // // This method is called when a new open view of an object is needed, // i.e. when an item in an object's Open submenu has been selected or // when an object is double clicked on. This is equivalent to selecting // the default item in the object's Open submenu. // //#****************************************************************************** //# Define metaclass data //#****************************************************************************** attribute HMODULE hmod; #ifdef __SOMIDL__ implementation { releaseorder: clsQueryModuleHandle; //# Class modifiers externalstem = hello; local; externalprefix = hloM_; majorversion = 1; minorversion = 2; filestem = hello; callstyle = oidl; dllname = "hello.dll"; //#****************************************************************************** //# Define overridden metaclass methods //#****************************************************************************** wpclsQueryDefaultView: override; // METHOD: wpclsQueryDefaultView // // DESCRIPTION: Returns the default view for a new instance // of this object. // // REMARKS: // // Return the ID of the default view, OPEN_HELLO. // This ID must be the same as the ID of the open // submenu item, ID_OPENHELLO. // // NOTES: // // This method is called to determine which view to open when an // object of class Hello is double clicked on. wpclsQueryTitle: override; // METHOD: wpclsQueryTitle // // DESCRIPTION: Return the string "Hello Workplace Shell". // // NOTES: // // This method is called by the Workplace Shell to determine the object // title when an object of class Hello is created. // }; /* End implementation */ #endif /* __SOMIDL__ */ }; ═══ 16.3.1.2. Source Code for Hello ═══ The following sample illustrates the source code (C): /* * This file was generated by the SOM Compiler and Emitter Framework. * Generated using SOM Emitter emitctm: 2.40 */ #ifndef SOM_Module_hello_Source #define SOM_Module_hello_Source #endif #define Hello_Class_Source #define M_Hello_Class_Source #define INCL_DOS #include "hello.ih" MRESULT EXPENTRY ClientWinProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); // Structure to pass the object pointer and // use list item to the window procedure typedef struct { WPObject *self; /* Pointer to the object */ USEITEM UseItem; /* Use list item header */ VIEWITEM ViewItem; /* Open view use list item */ } WINDOWDATA; typedef WINDOWDATA *PWINDOWDATA; /* * METHOD: wpFilterPopupMenu * * DESCRIPTION: Removes any menu items from the context menu that don't apply. * * HOW TO OVERRIDE: No restrictions. * * NOTES: * * This method is called when an object's context menu has been requested * (i.e. right click or S-F10 on an object) before displaying the menu. It * is called before wpModifyPopupMenu. */ SOM_Scope ULONG SOMLINK hlo_wpFilterPopupMenu(Hello somSelf, ULONG ulFlags, HWND hwndCnr, BOOL fMultiSelect) { /* HelloData *somThis = HelloGetData(somSelf); */ HelloMethodDebug("Hello","hlo_wpFilterPopupMenu"); // Return the parent class' menu bitstring minus the "move bit" return (parent_wpFilterPopupMenu(somSelf, ulFlags, hwndCnr, fMultiSelect) & ~CTXT_MOVE); } /* * METHOD: wpModifyPopupMenu * * DESCRIPTION: Adds the menu items to the context menu. * * NOTES: * * This method is called when an object's context menu has been requested * (i.e. right click or S-F10 on an object) before displaying the menu. It * is called after wpFilterPopupMenu. */ SOM_Scope BOOL SOMLINK hlo_wpModifyPopupMenu(Hello somSelf, HWND hwndMenu, HWND hwndCnr, ULONG iPosition) { HMODULE hmod; /* HelloData *somThis = HelloGetData(somSelf); */ HelloMethodDebug("Hello","hlo_wpModifyPopupMenu"); /* Get the module handle of the .DLL */ hmod = _clsQueryModuleHandle(_Hello); /* * Put the "Say Hello" submenu item in the Open submenu */ _wpInsertPopupMenuItems(somSelf, // Object hwndMenu, // Main context menu 0, // Position to insert menu at // 0 = top of menu hmod, // Module of menu to insert ID_OPENHELLO, // Menu to insert WPMENUID_OPEN); // Submenu to insert menu in /* * Put the "Product Info" menu item at the end of the main context menu */ _wpInsertPopupMenuItems(somSelf, // Object hwndMenu, // Main context menu iPosition, // Position to insert menu at // iPosition = next available hmod, // Module of menu to insert ID_MSGBOX, // Menu to insert 0); // Submenu to insert menu in // 0 = main context menu return (parent_wpModifyPopupMenu(somSelf, hwndMenu, hwndCnr, iPosition)); } /* * METHOD: wpMenuItemSelected * * DESCRIPTION: Processes input from the menu options that was added. * * NOTES: * * This method is called when an item in an objects' context menu has been * selected. */ SOM_Scope BOOL SOMLINK hlo_wpMenuItemSelected(Hello somSelf, HWND hwndFrame, ULONG ulMenuId) { /* HelloData *somThis = HelloGetData(somSelf); */ HelloMethodDebug("Hello","hlo_wpMenuItemSelected"); switch(ulMenuId) { case IDM_OPENHELLO: /* * Either the object was double clicked on or the Say Hello * item on the Open submenu was selected. * * We could call wpOpen here, but wpOpen will open a new view * no matter what. wpViewObject only opens a new view if * no open view exists or if mutliple concurrent views are enabled. * Otherwise, it will give focus to the current open view. * * wpViewObject should be used whenever possible instead of wpOpen * to prevent creating multiple open views inadvertently. */ _wpViewObject(somSelf, // Object NULLHANDLE, // Workplace Shell // internal use only OPEN_HELLO, // View to open. This ID must be the // same as the menu ID ID_OPENHELLO 0); // parameter passed to wpOpen break; case IDM_MSGBOX: { // Message Box menu item was selected WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Message box displayed from a Hello object's pop-up menu.", "Workplace Message", 1, MB_OK | MB_MOVEABLE | MB_INFORMATION); break; } default: return parent_wpMenuItemSelected(somSelf, hwndFrame, ulMenuId); } return TRUE; /* We processed it */ } /* * METHOD: wpOpen * * DESCRIPTION: Opens the Hello Workplace Shell window. * * NOTES: * * This method is called when a new open view of an object is needed, * i.e. when an item in an object's Open submenu has been selected or * when an object is double clicked on. This is equivalent to selecting * the default item in the object's Open submenu. * * wpOpen should always open a new view. The Workplace Shell actually * calls wpViewObject first when an object is double clicked on or an Open * submenu item is selected. wpViewObject will then call wpOpen if there * is currently no open view of the selected Open submenu item or if * mutliple concurrent views of the object are enabled. */ SOM_Scope HWND SOMLINK hlo_wpOpen(Hello somSelf, HWND hwndCnr, ULONG ulView, ULONG param) { /* HelloData *somThis = HelloGetData(somSelf); */ HelloMethodDebug("Hello","hlo_wpOpen"); switch (ulView) { case OPEN_HELLO: { // Request to open a Hello Workplace Shell window // Create a standard window HAB hab; // Anchor block handle HWND hwndClient; // Client window handle HWND hwndFrame; // Frame window handle PWINDOWDATA pWindowData; ULONG flCreate; // Window creation flags hab = WinQueryAnchorBlock(HWND_DESKTOP); // Create the class, adding a user word to the window data to // anchor the object use list item for this open view WinRegisterClass(hab, "hello", ClientWinProc, CS_SIZEREDRAW, sizeof(*pWindowData)); flCreate = FCF_SYSMENU | FCF_SIZEBORDER | FCF_TITLEBAR | FCF_MINMAX | FCF_SHELLPOSITION | FCF_TASKLIST; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &flCreate, "hello", _wpQueryTitle(somSelf), 0L, 0, ID_FRAME, &hwndClient); if (hwndFrame) { WinSetFocus(HWND_DESKTOP, hwndFrame); // Now that we have created an open view, add the view to the // object's use list. This use list is used by wpViewObject and // wpClose to check for existing open views. // Get storage for and initialize a use list item pWindowData = (PWINDOWDATA) _wpAllocMem(somSelf, sizeof(*pWindowData), NULL); memset((PVOID) pWindowData, 0, sizeof(*pWindowData)); pWindowData->self = somSelf; pWindowData->UseItem.type = USAGE_OPENVIEW; pWindowData->ViewItem.view = OPEN_HELLO; pWindowData->ViewItem.handle = hwndFrame; // Add the use list item to the object's use list _wpAddToObjUseList(somSelf, &(pWindowData->UseItem)); // Save the pointer to the use item in the window words so that // the window procedure can remove it from the list when the window // is closed WinSetWindowPtr(hwndClient, QWL_USER, pWindowData); } return hwndFrame; } // Some other view was requested. Pass the request on to the // parent (WPDataFile) class default: return (parent_wpOpen(somSelf, hwndCnr, ulView, param)); } /* end switch (ulView) */ } /* * METHOD: clsQueryModuleHandle * * DESCRIPTION: * * Returns the module handle of this class. If this is the * first invocation, DosQueryModuleHandle is called to save the handle * for future invocations. * * RETURN: * * 0 Unsuccessful * non-zero Module handle * * NOTES: * * This method is called when a new open view of an object is needed, * i.e. when an item in an object's Open submenu has been selected or * when an object is double clicked on. This is equivalent to selecting * the default item in the object's Open submenu. */ SOM_Scope HMODULE SOMLINK hloM_clsQueryModuleHandle(M_Hello somSelf) { M_HelloData *somThis = M_HelloGetData(somSelf); M_HelloMethodDebug("M_Hello","hloM_clsQueryModuleHandle"); // Make sure we already have the module handle if (_hmod == NULLHANDLE) { zString zsPathName; somId Id; // Retrieve registered path name of the module (DLL) // and query the module handle Id = somIdFromString("M_Hello"); zsPathName = _somLocateClassFile(SOMClassMgrObject, Id, M_Hello_MajorVersion, M_Hello_MinorVersion); SOMFree(Id); DosQueryModuleHandle(zsPathName, &_hmod); } return (_hmod); } /* * METHOD: wpclsQueryDefaultView * * DESCRIPTION: Returns the default view for a new instance of this object. * * REMARKS: * * Return the ID of the default view, OPEN_HELLO. This ID must be the * same as the ID of the Open submenu item, ID_OPENHELLO. * * NOTES: * * This method is called to determine which view to open when an object * of class Hello is double clicked on. */ SOM_Scope ULONG SOMLINK hloM_wpclsQueryDefaultView(M_Hello somSelf) { /* M_HelloData *somThis = M_HelloGetData(somSelf); */ M_HelloMethodDebug("M_Hello","hloM_wpclsQueryDefaultView"); return OPEN_HELLO; } /* * METHOD: wpclsQueryTitle * * DESCRIPTION: Returns the string "Hello Workplace Shell". * * NOTES: * * This method is called by the Workplace Shell to determine the object * title when an object of class Hello is created. */ SOM_Scope PSZ SOMLINK hloM_wpclsQueryTitle(M_Hello somSelf) { // M_HelloData *somThis = M_HelloGetData(somSelf); M_HelloMethodDebug("M_Hello","hloM_wpclsQueryTitle"); return "Hello Workplace Shell"; } /* * FUNCTION: ClientWinProc * * DESCRIPTION: Window procedure for the Hello, Workplace Shell window. */ MRESULT EXPENTRY ClientWinProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { BOOL fSuccess; // Return from function switch(msg) { case WM_PAINT: { HPS hps; // Cached PS RECTL rcl; // Window rectangle CHAR sz[25]; // String hps = WinBeginPaint (hwnd , (HPS)0, NULL); fSuccess = GpiErase (hps); WinQueryWindowRect (hwnd, &rcl); strcpy (sz, "Hello, Workplace Shell."); WinDrawText(hps, strlen(sz), sz, &rcl, CLR_BLACK, CLR_WHITE, DT_CENTER | DT_VCENTER); fSuccess = WinEndPaint (hps); return (MRESULT) NULL; } case WM_CLOSE: { // Get the object pointer and the use list item from the window PWINDOWDATA pWindowData = (PWINDOWDATA) WinQueryWindowPtr(hwnd, QWL_USER); // Remove this window from the object's use list _wpDeleteFromObjUseList(pWindowData->self,&pWindowData->UseItem); // Free the use list item. Note that there is no need to supply a // length since this storage was allocated with wpAllocMem _wpFreeMem(pWindowData->self,(PBYTE)pWindowData); // Destroy the window and return WinDestroyWindow(WinQueryWindow(hwnd, QW_PARENT)); return (MRESULT) NULL; } default: return WinDefWindowProc(hwnd, msg, mp1, mp2); } } ═══ 16.3.1.3. Resource Code for Hello ═══ The following sample illustrates the resource code (RC): #include "hello.ih" MENU ID_OPENHELLO LOADONCALL MOVEABLE DISCARDABLE BEGIN MENUITEM "~Say Hello", IDM_OPENHELLO END MENU ID_MSGBOX LOADONCALL MOVEABLE DISCARDABLE BEGIN MENUITEM "~Message Box", IDM_MSGBOX END ═══ 16.3.1.4. Make File for Hello ═══ The following sample illustrates the make file (MAK): all: hello.dll hello.dll: hello.obj hello.res link386 /co /noi /noe /m hello,hello.dll,,somtk pmwp.lib,hello.def; rc hello.res hello.dll hello.obj: hello.c icc /c /Ti /Kb /Gm /Ss /Ge- hello.c hello.res: hello.rc rc -r hello.rc ═══ 16.3.1.5. REXX Files for Hello ═══ The following shows the REXX command file for registering the Hello class: /* */ call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" call SysLoadFuncs say SysRegisterObjectClass("Hello", "C:\OS2\DLL\HELLO.DLL") The following shows the REXX command file for creating an instance of the Hello class: /* */ call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" call SysLoadFuncs say SysCreateObject("Hello",, "My Hello",, "",, "OBJECTID=") The following shows the REXX command file for deregistering the Hello class: /* */ call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs" call SysLoadFuncs say SysDeregisterObjectClass("Hello") ═══ 17. REXX Utility Workplace Shell Functions ═══ REXX combines the simplicity of a programming language such as BASIC with features that exist in more powerful languages such as C, PASCAL, or PL/1. Part of the success of REXX has been due in part to having been selected as the Systems Application Architecture Programming Language (SAA/PL). The purpose is to provide a common look and feel across all operating systems. This is important because CUA is the standard that the Workplace Shell uses which is also part of SAA. REXX provides the facility for the Workplace Shell to create, modify, and delete objects. This chapter describes the REXX functions and how to use them in Workplace Shell applications. ═══ 17.1. About REXX Utility Functions ═══ The power of REXX is often overlooked by many people as to how much benefits one can receive by using a command based language. REXX which stands for restructured extended executor was created to offer an easy way to ask the operating system to perform a special task without writing hundreds or sometimes thousands of lines of computer code to do the same task. The simplicity of REXX is by far its strongest point along with its ease of use. REXX provides the facility for the Workplace Shell to create, modify, and delete objects in a very simplistic way. REXXUTIL is a dynamic link library (REXXUTIL.DLL) that provides specific functionality to the Workplace Shell, which allows manipulating Workplace Shell classes as well as objects. A complete description of the commands can be found in the OS/2 Command Reference or the online version which is located in the OS/2 Information folder. To use a REXXUTIL function in a REXX program, you must first register the function using RxFuncAdd. However, you have the choice of either registering one function using RxFuncAdd or you can register all functions by first registering SysLoadFuncs using RxFuncAdd. The following example shows how to register a single function: call RxFuncAdd 'SysSetObjectData', 'RexxUtil', 'SysSetObjectData' The function SysSetObjectData is the only function in this case that is registered by RxFuncAdd. The following example shows how to register all of the functions using RxFuncAdd: call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' call SysLoadFuncs Using SysLoadFuncs allows all of the OS/2 sessions to use the REXXUTIL functions. ═══ 17.2. Using REXX Utility Functions ═══ There are useful functions that pertain to the object oriented Workplace Shell. REXXUTIL provides useful functions that allow the creation, destruction, and the altering of the properties of objects. These functions are listed as follows: o SysCreateObject o SysDestroyObject o SysSetObjectData o SysSetIconData o SysRegisterObjectClass o SysDeregisterObjectClass o SysQueryClassList o SysGetEa o SysPutEa o SysIni ═══ 17.2.1. Creating Objects ═══ The following figure shows the syntax of SysCreateObject: Syntax: SysCreateObject(class_name, title, location, ,