From: keith@taligent.com (Keith Rollin)
Subject: Re: Keeping a resource file open forever from an INIT
Followup-To: comp.sys.mac.programmer
Organization: Taligent
Date: Mon, 25 Jan 1993 02:21:29 GMT

In article <2L9WB4WS@cc.swarthmore.edu>, pbrande1@cc.swarthmore.edu (Philip
Brandenberger) wrote:
> 
> Hello all-- I hope this is blatantly FAQ.
> 
> I am working on an INIT in which I'd like to keep my resource file open
> forever much as Suitcase/MasterJuggler does for itself and its suitcases and
> as Carpetbag does also.  
> 
> I gather that the way to do this is to hack at the FCBs, but the whole
> process is a bit cloudy.  If anyone has sample code or a basic description
> that would be great.

Here's how I do it:

// --------------------
// A macro for patching traps. Follows my own naming conventions, so it
// may not be useful for you. But I include it for completeness.

#define PatchTheTrap(trapName, type) \
	old##trapName = (trapName##Proc) Get##type##TrapAddress(_##trapName); \
	Set##type##TrapAddress((long) My##trapName, _##trapName)

// --------------------
// The relevent parts of my INIT's startup code. I strip the PC according
// to Technote #245 (I don't know its name under the new TN scheme). I then
// roll my own RememberA0/SetUpA4, since it saves a few bytes. Next, I
patch
// InitAllPacks and remember what file I came from for later. Finally, I
// restore A4 and leave.

void	main()
{
	Ptr			ourAddress;
	Handle		ourHandle;
	Handle		show;
	
	asm {
		lea		@continue,A0		; Fix up the PC (TN #245)
		move.l	A0,D0
		StripAddress				; clean the PC
		move.l	D0,A0
		jmp		(A0)				; use the new PC
	@continue

		move.l	A4,-(sp)			; save orig A4
		bsr		__GetA4				; get pointer to save location into A1
		lea		main,A4				; get our A4
		move.l	A4,(A1)				; save it so SetUpA4() will work
		move.l	A4, ourAddress		; for the RecoverHandle, later
	}

	PatchTheTrap(InitAllPacks, Tool);
	RememberMe();

	RestoreA4();
}

// --------------------
// Remembers the name and location of the file owning the currently active
// resource map. This is stored in a global variable, which is a snap under
// THINK C. If you are using MPW, read Technote #256 or develop #12.

static void	RememberMe()
{
	FCBPBRec	pb;
	OSErr		err;

	pb.ioCompletion = nil;
	pb.ioNamePtr = gOurName;
	pb.ioVRefNum = 0;
	pb.ioRefNum = CurResFile();
	pb.ioFCBIndx = 0;
	
	err = PBGetFCBInfoSync(&pb);
	
	gOurVRefNum = pb.ioFCBVRefNum;
	gOurDirID = pb.ioFCBParID;
}

// --------------------
// InitAllPacks is called during the launching of an application. I take
this
// opportunity to re-open my INIT (since the system closes it after it was
// called during boot-up time).

static pascal void	MyInitAllPacks(void)
{
	SetUpA4();
	
	oldInitAllPacks();
	
	if (gMyRefNum == 0)
		OpenAndAddMe();
		
	RestoreA4();
}

// --------------------
// Tricky routine that opens a resource file and places the resource map
// BEHIND the system's. I want it behind the system resource file because I
// want it available even if the program calls UseResFile(0). Doing it this
// way also means that I only have to open the resource file once instead
of
// once per application.

pascal short InlineHOpenResFile(short vRefNum,long dirID,ConstStr255Param
fileName,
    char permission) = 0xA81A; 

static void	OpenAndAddMe()
{
	THz				currentZone;

	short			oldFile;
	short			refNum;
	ResMapHandle	current = nil;
	ResMapHandle	previous = nil;
	ResMapHandle	ourParent = nil;
	ResMapHandle	us = nil;
	ResMapHandle	system = nil;
	
	currentZone = GetZone();
	SetZone(SystemZone());

	oldFile = CurResFile();
	refNum = InlineHOpenResFile(gOurVRefNum, gOurDirID, gOurName, fsRdPerm);
	UseResFile(oldFile);
	
	if (refNum != -1) {

		current = (ResMapHandle) TopMapHndl;
		
		// First, find us (we should be on top)

		while ((current != nil) && ((**current).refNum != refNum)) {
			previous = current;
			current = (**current).nextMap;
		}
		if (current != nil) {
			ourParent = previous;
			us = current;
		}
		
		// Second, find the System
		
		system = (ResMapHandle) SysMapHndl;
		
		if ((us == nil) || (system == nil)) {
			CloseResFile(refNum);
		} else {
			if (ourParent != system) {
			
			//
			// Be sure to perform all these steps so that the
			// resource chain is never inconsistant or circular.
			// If that happens, debuggers like TMON will detonate.
			//
				if ((ResMapHandle) TopMapHndl == us)
					TopMapHndl = (void*) (**us).nextMap;
				if (ourParent)
					(**ourParent).nextMap = (**us).nextMap;
				(**us).nextMap = (**system).nextMap;
				(**system).nextMap = us;
			}
			gMyRefNum = refNum;
		}
	}
	SetZone(currentZone);
}


-----
Keith Rollin
Phantom Programmer
Taligent, Inc.
Newsgroups: comp.sys.mac.programmer