Source code for Macintosh Programming Secrets – Second Edition (1992)

Preamble

Source code from the second edition of Macintosh Programming Secrets (1992) by Scott Knaster

See also

Errata

MPW

Links

Notes

Chapter 3 – Getting the skeleton to work in MPW

Getting the skeleton to compile/build in MPW 3.2.3…

From the second edition, Listing 3-1 Standard_stuff.c and StandardStuff.h

Apart from the numerous typos in the text, which are fixed in the full listing at the end of the chapter…

Some header files are actually required that aren’t mentioned:

  • For EventRecord,
#include "Events.h"
#include <OSUtils.h> /* for GetTrapAddress() */

For inGrow and other Window events

#include "Windows.h"
  • For MenuHandle,
#include "Menus.h"
  • For Str255, short, etc.,
#include "Types.h"
  • For MAXLONG,
#include "Values.h"
  • For NIL, FALSE, TRUE,
    • StdDef.h has NULL
    • StdLib.h has NULL
    • AppleEvents.h has true, fals, and nil in lower case
    • MPW 3.2.3 seems to be missing MacTypes.h, which is here: jduerstock/mpw-headers/MacTypes.h, but there is an issue with LF/CR formatting in the downloaded ZIP, and copy/paste into BasiliskII doesn’t work (for whatever reason).
      • Line 52 also states that nil (note the lowercase) should be NULL
      • Line 254 states true and false (again in lowercase)
    • MPW 3.5 does have MacTypes.h, which also requires ConditionalMacros.h. However, there are some issues of “Enum ID previously declared”
    • NOTE: Changing to lower case solves the issue for nil, true, and  false. or just add the following #define lines:
#define TRUE true
#define FALSE false
#define NIL nil

It will now compile successfully!

Note, for NIL, we could also have defined instead (which is a common thing to do):

#define NIL 0L

However, it won’t build as we are still missing some header files… such as for TE, Dialogs, Disk and System, and so on…

Add the following

/* Stuff for building */
#include "TextEdit.h"
#include "Dialogs.h"
#include "DiskInit.h"
//#include "Disks.h"
#include "Files.h"
#include "Fonts.h"
#include "Desk.h"
//#include "Windows.h"
//#include "StandardFile.h"
//#include "OSEvents.h"
//#include "OSUtils.h"
//#include "Packages.h"
//#include "Processes.h"
//#include "QuickDraw.h"

Gets the errors down to just 4

#    case diskEvt:
#      HandleDiskEvent(event);
#                     ?        
### Warning 236 Calling function that has no definition
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 151
#--------------------------------------------------------------------------------------------------------------------------------
#      if (TrackGoAway(theWindow, event->where)){
#        CloseAnyWindow(FrontWindow());
#                      ?                
### Warning 236 Calling function that has no definition
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 232
#--------------------------------------------------------------------------------------------------------------------------------
#  SetCursor(&qd.arrow);
#  GetIndString(&theMessage, 128, errNumber);
#              ?                              
### Warning 236 Calling function that has no definition
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 370
#--------------------------------------------------------------------------------------------------------------------------------
#{
#  if (NGetTrapAddress(0xA86E, ToolTrap) == NGEtTrapAddress(0xAA6E, ToolTrap))
#                                                          ?                   
### Warning 236 Calling function that has no definition
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 438
#--------------------------------------------------------------------------------------------------------------------------------

blah

Next steps

HandleDiskEvent isn’t in any of the MPW header files (at least not from jduerstock/mpw-headers/)

Two of these are typos on my part:

  • HandleDiskEvent should be HandleDiskInsert
  • NGEtTrapAddress should be NGetTrapAddress

In HandleMouseDown() there is a disparity between the code in the explanatory text and the listing at the end of the chapter. The text shows:

    case inGoAway:
      if (TrackGoAway(theWindow, event-&gt;where)){
        CloseAnyWindow(FrontWindow());
      }
      break;

but the complete listing uses theWindow, which presumably comes from FindWindow() call:

    case inGoAway:
      if (TrackGoAway(theWindow, event-&gt;where)){
        /*CloseAnyWindow(FrontWindow());*/
        CloseAnyWindow(theWindow);
      }
      break;

However, the same “Calling function that has no definition” error appears. Again searching the MPW headers shows nothing, nor does a google search, apart from:

which aren’t Macintosh C related.

FindIndString() to the contrary, has a number of references:

After an actual “physical” search of the MPW3.2.3 directory, using the search tool in OSX/macOS/MacOS (or whatever it is called these days), GetIndString is declared in ToolUtils.h. So add

#include "ToolUtils.h"

That leaves just the CloseAnyWindow() issue!

# 11:01:47 PM ----- Build of StandardStuff.
# 11:01:47 PM ----- Analyzing dependencies.
# 11:01:47 PM ----- Executing build commands.
    C -r Standard_stuff.c
### Warning 254 Local variable "mouse" not used within the Body of the function :  MainEventLoop
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 137
#--------------------------------------------------------------------------------------------------------------------------------
#      if (TrackGoAway(theWindow, event->where)){
#        CloseAnyWindow(FrontWindow());
#                      ?                
### Warning 236 Calling function that has no definition
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 236
#--------------------------------------------------------------------------------------------------------------------------------
    Link -t APPL -c '????' Standard_stuff.c.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"CSANELib.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"Math.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"StdClib.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:Libraries:"Runtime.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:Libraries:"Interface.o -o StandardStuff
### Link: Error: Undefined entry, name: (Error 28) "CloseAnyWindow"
  Referenced from: HandleMouseDown in file: Standard_stuff.c.o
### Link: Errors prevented normal completion.
### MPW Shell - Execution of StandardStuff.makeout terminated.
### MPW Shell - Execution of BuildProgram terminated.

A similar “physical” text in OSX for CloseAnyWindow doesn’t reveal its location. Maybe it is a header in MPW 3.5?

In AppearenceSampleMain.c, in MPW-GM/MPW3.5/EWxampes/CarbonExamples/AppearenceSample/AppearenceSampleMain.c, there is the following “user defined” code

//———————————————————————————————————————————————————————————————————————————
//	• CloseAnyWindow
//———————————————————————————————————————————————————————————————————————————
//	Close the given window in a manner appropriate for that window. If the
//	window belongs to a DA, we call CloseDeakAcc. For dialogs, we simply hide
//	the window. If we had any document windows, we would probably call either
//	DisposeWindow or CloseWindow after disposing of any document data and/or
//	controls.
//	
static void
CloseAnyWindow( WindowPtr window )
{
	BaseWindow*		wind;
	
	if ( IsDAWindow( window ) )
	{
		// CloseDeskAcc( ((WindowPeek)window)->windowKind );
	}
	else if ( GetObjectFromWindow( window, &wind ) )
	{
		delete wind;
	}
	else
		DisposeWindow( window );
}

Upon a closer look,  any mention of CloseAnyWindow is missing from the text of the book (including the summary of the routines) – although it is present in both the listing 3-1 and listing 3-2 at the end of the chapter)! So, never trust the text and only follow the listings – is that the lesson to be learnt here?

/********************************************************************************

    CloseAnyWindow

    Close the given window in an manner appropriate for that window. If the
    window belongs to a DA, we call CloseDeskAcc. For dialogs, we simply hide
    the window. If we had any document windows, we would probably call either
    DisposeWindow or CloseWindow after disposing of any document data and/or
    controls.

********************************************************************************/

void CloseAnyWindow(WindowPtr window)
{
    if (IsDAWindow(window)) {
        CloseDeskAcc(((WindowPeek) window) ->windowKind);
    } else if (IsDialogWindow(window)) {
        HideWindow(window);
    } else if (IsAppWindow(window)) {
        /* Do something significant for document windows. */
    }
}

Then after that has been entered, the build complains that IsDialogWindow is missing. It is the same story (missing from the text, but is given in the listing(s)

/********************************************************************************

    IsDialogWindow

   Check to see if a window is a dialog window. We can determine this by
   checking to see if the windowKind field is equal to dialogKind.

********************************************************************************/
Boolean IsDialogWindow(WindowPtr window)
{
    if (window==NIL)
        return FALSE;
    else
        return (((WindowPeek)window)->windowKind == dialogKind);
}

Finally success!

# 11:50:41 PM ----- Build of StandardStuff.
# 11:50:41 PM ----- Analyzing dependencies.
# 11:50:42 PM ----- Executing build commands.
    C -r Standard_stuff.c
### Warning 254 Local variable "mouse" not used within the Body of the function :  MainEventLoop
#--------------------------------------------------------------------------------------------------------------------------------
    File "Standard_stuff.c"; Line 137
#--------------------------------------------------------------------------------------------------------------------------------
    Link -t APPL -c '????' Standard_stuff.c.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"CSANELib.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"Math.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:"StdClib.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:Libraries:"Runtime.o "MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:Libraries:"Interface.o -o StandardStuff
### Link: Warning: File was not needed for link: (Error 52) MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:CSANELib.o
### Link: Warning: File was not needed for link: (Error 52) MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:Math.o
### Link: Warning: File was not needed for link: (Error 52) MPW_3.2.3:MPW_3.2.3:MPW_Update:MPW_3.2.3:Libraries:CLibraries:StdClib.o
# 11:50:44 PM ----- Done.
	StandardStuff 

Chapter 3 – Getting the skeleton to work in Think C

Continuing where we left off in MPW, but continuing in ThinkC… this is a lot easier. However, what is strange is that a few typos were detected in ThinkC than MPW seemed to ignore and compiled and built an application anyway (albeit that the application didn’t work, ewith error -192 or the application just opened and quit immediately (crashed?)).

After fixing the typos, and then running, the application still quits immediately (crashes). After some thought, I realised it is because no resource file is provided. Looking at the code, only four resources are required, one MBAR (128) linking the three MENU resources (128, 129 and 130) for the Apple, File and Edit menus. Their items can be deduced from the StandardStuff.h file.

Once the resource file is made then the application runs perfectly..! This .res file might work (untested)

/* StandardStuff.h                                     */
/* Taken from Creation.r from Programmers Guide to MPW */

#include "Types.r"; 
#include "SysTypes.r" 
#include "StandardStuff.h"

resource 'MBAR' (rMenuBar, preload) {
    { mApple, mFile, mEdit };
};

resource 'MENU' (mApple, preload) {
    mApple, textMenuProc,
    0b1111111111111111111111111111101, /* disable dashed line, */enabled, apple,/* enable About and DAs*/
    {
        "About...",
            noicon, nokey, nomark, plain;
        "-",
            noicon, nokey, nomark, plain
    }
};

resource 'MENU' (mFile, preload) {
    mFile, textMenuProc, 0b1111111111111111111101100001000, enabled, "File",
    {
        "New",
            noicon, "N", nomark, plain;
        "Open",
            noicon, "O", nomark, plain;
        "-",
            noicon, nokey, nomark, plain; 
        "Close",
            noicon, "W", nomark, plain; 
        "Save",
            noicon, "S", nomark, plain; 
        "Save As...",
            noicon, nokey, nomark, plain; 
        "Revert",
            noicon, nokey, nomark, plain;
        "-",
            noicon, nokey, nomark, plain; 
        "Page Setup...",
            noicon, nokey, nomark, plain; 
        "Print...",
            noicon, nokey, nomark, plain;
        "-",
            noicon, nokey, nomark, plain; 
        "Quit",
            noicon, "Q", nomark, plain
    }
};

resource 'MENU' (mEdit, preload) {

mEdit, textMenuProc, 0b1111111111111111111111110111101, enabled, "Edit",
    {
        "Undo",
            noicon, "Z", nomark, plain;
        "-",
            noicon, nokey, nomark, plain; 
        "Cut",
            noicon, "X", nomark, plain;

        "Copy",
            noicon, "C", nomark, plain;
        "Paste",
            noicon, "V", nomark, plain;
        "Clear",
            noicon, "B", nomark, plain;
    }
};


resource 'SIZE' (-1) { /* MultiFinder-aware application */
    dontSaveScreen,
    acceptSuspendResumeEvents,
    enableOptionSwitch,
    canBackground,
    multiFinderAware,
    backgroundAndForeground,
    dontGetFrontClicks,
    ignoreChildDiedEvents,
    not32BitCompatible,
    reserved, reserved, reserved, reserved, reserved, reserved, reserved, 
    96*1024,
    64*1024
};

blah

Chapter 4

Changes to StandardStuff.c

See also (or move from) Errata – Macintosh Programming Secrets (1992), the section Guessing AdjustMenus().

  • Need to sleepyTime, which is a long, so long sleepyTime; is needed in MainEventLoop()

This is the end, my friend

Leave a comment