Instructions - The HyperCard XCMD Examples Copyright Apple Computer, Inc. 1988 All rights reserved. About the Examples MPW 3.0 introduces a consistent interface to callback HyperCard routines from within XCMDs and XFCNs. The HyperCard XCMD Examples are intended to introduce the use these routines. More importantly, they are to serve as models for good software development of XCMDs and XFCNs using MPW 3.0. We provide examples of both an XCMC and an XFCN written in all three languages provided by Apple Computer, Inc. as part of the Macintosh Programmer's Workshop: assembler, C and Pascal. The files provided with this set of examples is: LittleDialog.a - sample XCMD to display a dialog box in assembler. LittleDialog.c - sample XCMD to display a dialog box in C. LittleDialog.p - sample XCMD to display a dialog box in Pascal. LittleDialog.r - resources for assembler, C or Pascal LittleDialog. Reduce.a - sample XFCN removing tabs and spaces in assembler. Reduce.c - sample XFCN removing tabs and spaces in C. Reduce.p - sample XFCN removing tabs and spaces in Pascal. Make - script to build and install the above XCMDs. 'HyperXExample Stack' - minimal stack to test XCMDs and XFCNs. They will rely upon the following interfaces and library: {AIncludes}HyperXCmd.a {CIncludes}HyperXCmd.h {PInterfaces}HyperXCmd.p {Libraries}HyperXLib.o Note that these files are different from those provided with the original HyperCard Toolkit released through APDA. The differances are: HyperXCmd.p: HyperXCmd.p declares the functions and procedures necessary to access the code in HyperXLib.o. THESE ROUTINE DECLARATIONS ARE DIFFERANT FROM THOSE WITH THE SAME NAME RELEASED THROUGH APDA: In all cases, the XCmdPtr passed by HyperCard to the XCMD must now be an additional parameter passed on to the library routines. Additionally, several commands were changed to match the internal workings of HyperCard itself: All Str31 values are really Str255. Plus the former functions, BoolToStr, ExtToStr, LongToStr, NumToStr & NumToHex, are now all procedures that take a VAR parameter. As a bonus, we have added the call: SendHCMessage. THE HYPERCARD TOOLKIT FILE XCmdGlue.inc IS NO LONGER USED! HyperXCmd.h: HyperXCmd.h also declares the functions necessary to access the code in HyperXLib.o. Only in some cases are these routine declarations differant from those with the same name released through APDA: Parameters that were StringPtr or Str31 values are now specified as either char * or Str255. THE HYPERCARD TOOLKIT FILE XCmdGlue.inc.c ALSO IS NO LONGER USED! Building the Examples Provided with the HyperCard examples is an MPW script file, Make. In order to build the examples, you must type "make" followed by the filename and then press the enter key. The build script knows the build rules for LittleDialog.a, LittleDialog.c, LittleDialog.p, Reduce.a, Reduce.c, and Reduce.p. It will then produce command lines to assemble, compile, link, or rez the source code and install the finished XCMD directly in the test stack. Select these lines and press enter again to complete the build process. Because this process uses a script which overrides the Make tool, it should be located in the current directory with the XCMD source. Writing Your Own XCMDs Within a stack, each XCMD must have a resource id that differs from all other XCMDs in that stack. The same is true for XFCNs. Choose a unique resource id for your XCMD and add it and the name of your file to the Make script. HyperCard actually accesses XCMDs by calling GetNamedResource. This requires the name of the resource to be the same as the command. When the linker creates the XCMD or XFCN resource, it uses the name of the code segment as its default resource name. The Make script sets the name of the segment to be the same as the file name by using the linker's -sg option. Thus the file name should be the same as you want the command name to be. The XCMD must be a single code segment. The main procedure has the form: PROCEDURE EntryPoint(paramPtr: XCmdPtr); This is a Pascal style procedure, so the XCMD itself is responsible for removing the parameter from the stack. In C, we accomplish this by defining the routine as: pascal void EntryPoint(XCmdPtr paramPtr); HyperCard executes the XCMD by jumping to the beginning of it so the entry point to the code must be the first thing. This is no problem for assembler and C, where the main segment can simply be placed first. In Pascal, however, this may not be sufficient. If the main procedure has nested functions, they will be compiled before the main code. We get around this by having a dummy first procedure with no nested routines, which then calls the real XCMD code: PROCEDURE RealXCMD(paramPtr: XCmdPtr); FORWARD; PROCEDURE EntryPoint(paramPtr: XCmdPtr); BEGIN RealXCMD(paramPtr); END; PROCEDURE RealXCMD(paramPtr: XCmdPtr); BEGIN ... END; The initial FORWARD declaration of RealXCMD allows us to call the real XCMD procedure from EntryPoint, but does not generate any code. The advantage of allowing nested procedures is the ability to share variables between routines without passing them as arguments. This is because NO GLOBAL VARIABLES are allowed for an XCMD. Since the default storage for strings in MPW C is along with the globals, it is necessary to use the -b option introduced with MPW 3.0 C in order to include the string data with the code resource. Having mentioned placement of string data within the code resource, it is necessary to emphasize that it is recommended that strings be placed as resources. This allows easy addaptation of stacks with XCMCs to international locations. Unfortunately, at this time,HyperCard does not have a convention for resources belonging to XCMDs or XFCNs. Currently using a resource mover to copy the XCMD or XFCN to another stack can leave needed resources behind. There are two things that can be done to help prevent such errors: 1. To indicate that a resource may belong to an XCMD, the example LittleDialog uses resources having the same id number as the XCMD itself. This is not a complete solution since it will not work for an XCMD which has more than one resource of a given type. This is therefor only a suggestion until a better means of bundling XCMDs with other resources is developed. 2. Within the code of the XCMD, always check for the availability of of the resource before it is to be used. Then, if the resource is missing, report it as an error that indicates what resource is missing. The linker must be provided with the name of a main code segment so it can stip unused code (mostly from the libraries we link with) from our XCMDs. Our Make script includes the linker option -m ENTRYPOINT. The linker is case sensitive, but Pascal symbols, C functions cast as "pascal", and the default case for assembler symbols are not case sensitive, i.e. converted to all upper-case, our main entry point for the linker should be in all upper-case also. XCMDs do not require the main routine to be named EntryPoint. However, since that was the name invented for the dummy pascal entry procedure, we have used it as the default name in our script. It was due to this agreeing with the scipt that all the examples here have main routines named EntryPoint. In Conclusion In keeping with HyperCard's efforts to make program development easier on the Macintosh, we have tried to introduce a more uniform method of creating XCMDs to expand the utility of HyperCard. Good luck and have fun!