• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Problem with example in Macintosh Programming Primer

PB170

Well-known member
Has anyone here successfully run the Reminder app from Dave Mark's and Cartwright Reed's "Macintosh C Programming Primer, Volume 1, Second edition"?

When checking the syntax, Think C complains that "Pointer types do not match" in the two lines below.

      GetDItem( dialog, iLaunchCheckBox, &itemType, &itemHandle, &itemRect );
      if ( reminder->launch = GetCtlValue( (ControlHandle)itemHandle ) )
              reminder->notify.nmResp = &LaunchResponse;
      else
              reminder->notify.nmResp = &NormalResponse;


I find this peculiar since I'm using the very same version of Think C as in the book (version 5), although there's a setting to turn off the pointer check that might explain it. After looking into it, I fixed it with a typecast (NMProcPtr) in front of &LaunchResponse and &NormalResponse so that the program compiles.

However, the program doesn't work like it's supposed to. This far all the example programs have worked fine (except from a small omission in the book at one point). Since I haven't got access to the source codes, I've (painstakingly) copied them from the OCR-scanned version at vintageapple.org and manually gone though and corrected and structured them, so it's possibly that some typo remains, although I've gone through the code so many times now that I doubt it, and it compiles just fine.

Are there bugs in the printed code, or could it be some setting in Think C that causes the issues?

The following happens:

Algorithm:

  • When setting reminders, the minutes are not copied properly to the submenu and sometimes results in a long string of random text (seems to happen when the minutes popup is set to '00').
  • The reminders go off at the wrong time (it seems like the minutes setting is ignored)
  • The OK button doesn't get greyed out when the text field is empty unless of the checkboxes are clicked
  • The Edit menu isn't initially disabled like it's supposed to (don't know where in the code/resource this should take place this at this point)



Interface:

  • The texts don't fit in the popups like in the book (although they do so when running the app under Mac OS 9…).



I'm assuming the two first issues are related to this part of the code in some way:

GetDItem( dialog, iHoursPopup, &itemType, &itemHandle, &itemRect );
val = GetCtlValue( (ControlHandle)itemHandle );
NumToString( (long)val, string );
StringToNum( string, &tmp );
reminder->hour = tmp;

reminder->menuString[0] = 0;
ConcatString( reminder->menuString, string );
ConcatString( reminder->menuString, "\p:" );

GetDItem( dialog, iMinutesPopup, &itemType, &itemHandle, &itemRect );
val = GetCtlValue( (ControlHandle)itemHandle );
menu = GetMHandle( mMinutes );
GetItem( menu, val, string );
StringToNum( string, &tmp );
reminder->minute = tmp;

ConcatString( reminder->menuString, string );
ConcatString( reminder->menuString, "\p " );

GetDItem( dialog, iAMorPMPopup, &itemType, &itemHandle, &itemRect );
val = GetCtlValue( (ControlHandle)itemHandle );

if ( val == kPM )
reminder->hour += 12;

menu = GetMenu( mAMorPM );
GetItem( menu, val, string );
ConcatString( reminder->menuString, string );

reminder->notify.qType = nmType;
reminder->notify.nmMark = kMarkApp;
}


// ConcatString

void ConcatString( Str255 str1, Str255 str2 )
{
short i;

for (i=str1[0]; i<str2[0]+str1[0]; i++)
{
str1[i+1] = str2[i-str1[0]+1];
}
str1[0] = i;
}


Does anyone have any thoughts about this? Kind of frustrating to have to debug the example code :)

I've attached the complete source code and resource file for reference.

View attachment Reminder.c

View attachment Reminder.π.rsrc.sit

 

dcr

Well-known member
Can't help but I can share in your misery.  I remember a book long ago for programming in BASIC.  You had to type in the code from the book-- no examples on floppy.  And I remember this one program--I think it was something somewhat lengthy, maybe two to four pages in length--and I typed it all in and it wouldn't work.  And I checked and re-checked for typos or any minor errors and still no go.  As I recall, I never did get it to work.

 

PB170

Well-known member
Can't help but I can share in your misery.  I remember a book long ago for programming in BASIC.  You had to type in the code from the book-- no examples on floppy.  And I remember this one program--I think it was something somewhat lengthy, maybe two to four pages in length--and I typed it all in and it wouldn't work.  And I checked and re-checked for typos or any minor errors and still no go.  As I recall, I never did get it to work.
Haha :) Well, it's been going quite well up until now. I hope with some help here, I can make this one work properly too :) Thanks for sharing the story :)

 

Crutch

Well-known member
The typecast is the right fix to your first issue.  Might be a THINK C compiler setting somewhere.  No big deal, a common thing to have to change in code as compilers evolved during the 68k era.

To have the Edit menu initially disabled, disable the menu itself in the appropriate MENU resource.  You can do this in ResEdit, assuming you are loading your menus from a resource file.  If you’re building the menu yourself, add a leading left paren to the menu title:  change “Edit” to “(Edit”.  (Still having this memorized is a really useful skill for me in 2020, by the way...)

The code to the get pop up menu text looks generally reasonable, is it possible iMinutes is set wrong i.e. you’re accidentally trying to pull that string from the wrong-number dialog item?

 

PB170

Well-known member
The typecast is the right fix to your first issue.  Might be a THINK C compiler setting somewhere.  No big deal, a common thing to have to change in code as compilers evolved during the 68k era.

To have the Edit menu initially disabled, disable the menu itself in the appropriate MENU resource.  You can do this in ResEdit, assuming you are loading your menus from a resource file.  If you’re building the menu yourself, add a leading left paren to the menu title:  change “Edit” to “(Edit”.  (Still having this memorized is a really useful skill for me in 2020, by the way...)

The code to the get pop up menu text looks generally reasonable, is it possible iMinutes is set wrong i.e. you’re accidentally trying to pull that string from the wrong-number dialog item?
Disabling the menu in ResEdit fixed the menu's behavior. Apparently something they missed in the otherwise fairly detailed instructions in the book. (I'm just blindly following instructions here :) )

All of the three time constants correspond to the right item numbers, so that's probably not the issue, unfortunately.

Thanks!

 

cheesestraws

Well-known member
I'd forgotten how nasty THINK C was to use.

The line:

menu = GetMHandle( mMinutes )


seems to be returning nil; you might want to start there?

 

Crutch

Well-known member
Good catch, but pretty sure that’s not the right fix.

This code is weird.  It’s using GetMHandle() for minutes, and GetMenu() for AM/PM.

Per Inside Macintosh you should only be calling GetMenu() once for each menu.  It loads the menu resource each time.  If you repeatedly call GetMenu() you are, I think, literally loading another menu resource into memory each time.  That will actually work if the items are named correctly ... but it’s a memory leak.

GetMHandle() is the right call to use here.  But it takes a menu ID, not a resource ID.

What is the value of mMinutes?  I bet it doesn’t correspond to the correct menu ID of the minutes pop up menu (it probably matches the resource ID) ... so GetMHandle() isn’t finding the menu.

 
Last edited by a moderator:

cheesestraws

Well-known member
What is the value of mMinutes?  I bet it’s a resource ID like 128 ... so GetMHandle() isn’t finding the menu.
Yes, it is a resource ID.  And yeah, I was pretty much just looking at how this code differed from the code in the blocks around it and seeing if making things line up made the bugs go away.  A time-honoured but unsubtle procedure :) .

Honestly, I find it really weird that this code is loading the minutes from the menu rather than just doing something like val * 5 and then using sprintf to generate the menu text... so yes, this code doesn't seem very nice.

 
Last edited by a moderator:

Crutch

Well-known member
Totally agree. The custom built strcat alternative is also weird. Why not just use BlockMove() and update the length byte, or ....

 

PB170

Well-known member
Thank you both very much for taking your time.

I'm learning as I go along here!

This code is weird.  It’s using GetMHandle() for minutes, and GetMenu() for AM/PM. 
Yeah, I noticed that too. I assumed it was just to show different ways to accomplish the same thing.

Strange – and a bit disappointing… I had the impression that Dave Mark's programming books were respected, and I've found it well written and fairly easy to follow this far.

Can I ask any of you take a moment and change this part of the code to something that makes more sense? While I'm writing my own programs as well as I go along, I'm using this as a reference / learning material, so I'd rather not change it myself.

 

PB170

Well-known member
I'd forgotten how nasty THINK C was to use.
It's pretty much all I know at this point, although I've had some glances at Xcode and Visual Studio to not be entirely stuck in the past :D  

Why nasty, by the way? Apart from the apparent lack of everything modern, that is :)  

 

PB170

Well-known member
This is the book everyone used back then though. Including me. 
Is there any other book you could recommend over this one?

Or is it just a matter of taking in as much as possible, gaining experience and then slowly begin to make your own judgments and decisions? :)

 

cheesestraws

Well-known member
I really don't mind the absence of syntax highlighting too much, to be honest.  It is nice, but not obligatory.  But honestly I'm still perfectly happy writing code in BBEdit Lite.

I suppose in my head I'm kind of comparing it with the THINK Pascal that I used to use, which had things like actual integration between the debugger and editor (though it also did really, really odd things with syntax hilighting).  That said, I think that version of TP was a few years later than THINK C 5.0, so I may just be being unfair.

 
Top