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!
