[comp.sys.mac.programmer] Check DialogPtr returned by GetNewDialog?=YES + DETAILED SOLUTION

ari@eleazar.dartmouth.edu (Ari Halberstadt) (04/06/91)

Several months ago I posted a solution to this problem: use ResErrProc,
in combination with the Signals described in some TechNotes. I even
implemented this and it worked. Testing for resource availability at
startup is not acceptable for several reasons, most of which boil down
to disk errors, though a few can be traced to low memory situations.

 A. The disk containing the application could have been placed offline.
This can happen by ejecting a removable media, just as a floppy or
a CD-ROM. The System will attempt to remount the disk, but the user
can override this with command-period. The disk could go offline if
it's accessed via a network and the network fails, or if the server
dies; there is little the System can do in such situations.

 B. There may not be anough memory to create the dialog.

The minimal solution to the first problem is:

 1. Make sure the 'DLOG' resource is loaded and is not a nil handle
    (see step 3 for  some comments on making sure there is memory for
	  the resource).

 2. Do the same for the 'DITL' resource.

Always check the result of GetNewDialog: while it may ignore errors
today, some hacker at Apple with a few spare hours may decide to fix
GetNewDialog. Version 50.0.3 of the Mac OS may actually check for
errors, which your well written application will catch.

These first few steps are really quite easy to do, and should catch
nearly all errors. For the pedants amongst us, the following steps
will make our applications even more robust.

 3. Allocate a pointer to contain the dialog, after making sure that
there will still be enough memory for your application's other needs.
While it's hard to know how much the window manager will need for its
own purposes (eg, the visRgn), your application should have a grow
zone function which can access at least 32K of reserved memory. When
you explicitely allocate memory, first turn on a flag preventing
access to your memory reserves, call NewHandle (or NewPtr), then reset
the flag. You simply must promise to check all error returns from the
memory manager. The large block of reserved memory ensures that
ToolBox calls that do not check for nil returns from the memory
manager (eg, GetNewDialog) will never encounter an out-of-memory
situation. To prevent depletion of your memory reserves when loading a
resource, you should set ResLoad to false, get the resource size, make
sure you have the memory, then restore ResLoad and load the resource.
Once every time through the event loop (or only on null events) make
sure that your memory reserves are topped off, and perhaps issue a
warning if they have been tapped.

 4. Save the current value of ResErrProc, and install your own
ResErrProc which will do a non-local goto to some safe location,
either the top of the event loop, or, preferably, immediately after
the GetNewDialog call.

 5. Call GetNewDialog, passing it the pointer allocated in step 3.

 6. Restore the value of ResErrProc. Then check the value returned by
GetNewDialog; if it's nil go to the same place your ResErrProc you
have gone (don't use a goto for this, use an if statement).

 7. If the dialog pointer is nil, try to display an error message. The
safest way to do this is to avoid using the resource manager, since
that is probably what caused the error in the first place. There are
two alternatives: create a "fake" alert by creating your own window,
icon, and buttons; or create a dialog at startup. I use the "fake"
alert solution, and it really isn't that difficult. You should create
the alert at the start of your application, when you know you have
enough memory, and just make it invisible until the error occurs. The
second alternative is to create an error dialog when your application
starts up using the dialog manager (simply ExitToShell at this point
if there's an error), and keep the dialog hidden as before; keep the
dialog simple, so that the only resources it needs to access can be
loaded into memory and made unpurgeable.  Do *not* use CouldDialog, as
it does not guarantee that there will be memory for the window when you
later call GetNewDialog, and the trap is no longer supported in System 7.0.

8. Recover from the dialog error as appropriate for your application.
Either jump directly to the top of your main event loop, or have the
function that attempted to create the dialog recover from the error by
aborting whatever was in progress and returning control to its caller.
I prefer the second solution, since the error may occur during the
"Save changes before quitting" alert; this is a critical time, and the
application should make every effort to abort the operation without
losing the user's work.

While recovering from dialog manager errors is a little trickier than
recovering from other errors, in practice, though, a well written
application will already include most, if not all (or even more) of
the above suggestions for proper error recovery. The only difference
in error checking when using the GetNewDialog call is that the
programmer should surround the call with the appropriate use of
ResErrProc.

gurgle@well.sf.ca.us (Pete Gontier) (04/09/91)

In article <1991Apr5.225347.3100@dartvax.dartmouth.edu> ari@eleazar.dartmouth.edu (Ari Halberstadt) writes:
> A. The disk containing the application could have been placed offline.
> B. There may not be anough memory to create the dialog.
> 1. Make sure the 'DLOG' resource is loaded and is not a nil handle
> 2. Do the same for the 'DITL' resource.
> 3. Allocate a pointer to contain the dialog, after making sure that
> 4. Save the current value of ResErrProc, and install your own
> 5. Call GetNewDialog, passing it the pointer allocated in step 3.
> 6. Restore the value of ResErrProc. Then check the value returned by
> 7. If the dialog pointer is nil, try to display an error message. The
>8. Recover from the dialog error as appropriate for your application.

Maybe I'm missing something here, but whatever happened to...

	GetNewDialog, check for a nil pointer
	ResError
	MemError

On failure, make an appeal to either...

	an earlier CouldAlert
	Notification Manager
-- 
 Pete Gontier, gurgle@well.sf.ca.us
 Software Imagineer, Kiwi Software, Inc.

d88-jwa@byse.nada.kth.se (Jon W{tte) (04/09/91)

In article <24101@well.sf.ca.us> gurgle@well.sf.ca.us (Pete Gontier) writes:

	   an earlier CouldAlert

CouldAlert is discontinued starting right now (i.e. Sys version 7)

							h+@nada.kth.se
							Jon W{tte
--
          I remain: h+@nada.kth.se (Jon W{tte) (Yes, a brace !)
"It's not entirely useless. I came in this great cardboard box !" - Calvin
"Life should be more like TV. I think all women should wear tight clothes,
       and all men should carry powerful handguns" - Calvin, again