olson@bootsie.uucp (Eric K. Olson) (02/15/91)
If you do GetResource() for a resource that is currently in memory,
you get a Handle to the data as it appears in memory. Is it possible,
without disturbing the resource in memory, to get the resource data
as it appears on the disk? Something like:
SetResLoad(FALSE);
resHand = GetResource(type, id);
SetResLoad(TRUE);
if (*resHand!=NULL) { /* The resource was loaded */
DetatchResource(resHand);
onDiskHand = GetResource(type, id);
DetachResource(onDiskHand);
ReattachResource(resHand, type, id);
}
Would work, if the call ReattachResource() existed. I don't think
there is any way to do this. Any ideas?
-Eric
--
Eric K. Olson, Editor, Prepare() NOTE: olson@bootsie.uucp doesn't work
Lexington Software Design Internet: olson@endor.harvard.edu
72A Lowell St., Lexington, MA 02173 Uucp: harvard!endor!olson
(617) 863-9624 Bitnet: OLSON@HARVARD
time@ice.com (02/15/91)
In article <1991Feb15.110116.5508@bootsie.uucp>, olson@bootsie.uucp (Eric K. Olson) writes: > SetResLoad(FALSE); > resHand = GetResource(type, id); > SetResLoad(TRUE); > if (*resHand!=NULL) { /* The resource was loaded */ > DetatchResource(resHand); > onDiskHand = GetResource(type, id); > DetachResource(onDiskHand); > ReattachResource(resHand, type, id); > } > > In article <1991Feb15.110116.5508@bootsie.uucp> you write: > SetResLoad(FALSE); > resHand = GetResource(type, id); > SetResLoad(TRUE); > if (*resHand!=NULL) { /* The resource was loaded */ > DetatchResource(resHand); > onDiskHand = GetResource(type, id); > DetachResource(onDiskHand); > ReattachResource(resHand, type, id); > } How about: SetResLoad(FALSE); resHand = GetResource(type, id); SetResLoad(TRUE); if (*resHand!=NULL) { /* The resource was loaded */ DetatchResource(resHand); onDiskHand = GetResource(type, id); DetachResource(onDiskHand); /* Now move that resource back into place... */ onDiskHand2 = GetResource(type, id); SizeResource(onDiskHand2, GetHandleSize(resHand)); BlockMove(*resHand, *onDiskHand2, GetHandleSize(resHand)); ChangedResource(resHand); } sound right? tim. ------------------------------------------------------------- Tim Endres | time@ice.com ICE Engineering | uupsi!ice.com!time 8840 Main Street | Voice FAX Whitmore Lake MI. 48189 | (313) 449 8288 (313) 449 9208
olson@bootsie.uucp (Eric K. Olson) (02/17/91)
In article <1CE00001.ed5n0r@tbomb.ice.com> time@ice.com writes: >How about: > SetResLoad(FALSE); > resHand = GetResource(type, id); > SetResLoad(TRUE); > if (*resHand!=NULL) { /* The resource was loaded */ > DetatchResource(resHand); > onDiskHand = GetResource(type, id); > DetachResource(onDiskHand); > /* Now move that resource back into place... */ > onDiskHand2 = GetResource(type, id); > SizeResource(onDiskHand2, GetHandleSize(resHand)); > BlockMove(*resHand, *onDiskHand2, GetHandleSize(resHand)); > ChangedResource(resHand); > } > >sound right? At first I thought this was a really good solution, but it doesn't do quite what my theoretical ReattachHandle() would. I don't understand the call to ChangedResource(resHand): wouldn't that just fail (it's no longer a Resource Handle)? If you meant ChangedResource(onDiskHand2), it doesn't reattach resHand. Any other old reference to the resource via resHand remains detached. New references via GetResource() return a different Handle (onDiskHand2). Calls to LoadResource() with the old Handle will fail. Please correct me if I'm wrong. My purpose for this is editting (or just copying) the currently running application's MENU resources. I don't need the changes to take effect until the next run (for editting). I _do_ need the resource as it appears on disk, even though it is in memory and not purgable (and modified from the data on the disk by the TCL). -Eric -- Eric K. Olson, Editor, Prepare() NOTE: olson@bootsie.uucp doesn't work Lexington Software Design Internet: olson@endor.harvard.edu 72A Lowell St., Lexington, MA 02173 Uucp: harvard!endor!olson (617) 863-9624 Bitnet: OLSON@HARVARD
olson@bootsie.uucp (Eric K. Olson) (02/17/91)
Well, I went ahead and brute-forced it. The following code allows me to load the Resource data off the disk, even if the resource is currently loaded and in use (such as 'MENU' resources of the currently running application). Unfortunately, it uses things that are likely to break: internal structures of the Resource Manager, and the TopMapHndl low-memory global. I don't know if these things are likely to change soon, or if they are available under AU/X. Isn't there a better way? Is this what AddReference() once did? typedef struct resMapHeaderRec { long dataOffset; long mapOffset; long dataLength; long mapLength; } resMapHeaderRec; typedef struct resMapRec { resMapHeaderRec header; struct resMapRec * * nextMap; short refNum; short attrib; unsigned short typeOffset; unsigned short nameOffset; } resMapRec, *resMapPtr, **resMapHandle; typedef struct resMapEntryRec { short resID; unsigned short nameOffset; unsigned long lengthOffset; Handle resHandle; } resMapEntryRec, *resMapEntryPtr, **resMapEntryHandle; Handle GetResDataFromDisk(type,id) ResType type; short id; { Handle onDiskHand; unsigned long resMapOffset; resMapEntryPtr resMapEntry; resMapPtr resMap; short inMemRef; Handle inMemHandle; SetResLoad(FALSE); inMemHandle = GetResource(type, id); SetResLoad(TRUE); if (*inMemHandle == NULL) { inMemRef = HomeResFile(inMemHandle); resMapOffset = RsrcMapEntry(inMemHandle); resMap = (resMapPtr) *TopMapHndl; /* Find the appropriate resource map */ while (resMap->refNum != inMemRef) { resMap = *(resMap->nextMap); if (resMap==NULL) return NULL; } resMapEntry = (resMapEntryPtr) (((Ptr) resMap) + resMapOffset); if (resMapEntry->resHandle!=inMemHandle) return NULL; DetachResource(inMemHandle); /* resMapEntry->resHandle = NULL; */ onDiskHand = GetResource(type, id); if (onDiskHand != NULL) { DetachResource(onDiskHand); HNoPurge(onDiskHand); } /* Reattach the old resource handle */ resMapEntry->resHandle = inMemHandle; } else { /* The normal GetResource case */ onDiskHand = GetResource(type, id); if (onDiskHand != NULL) { DetachResource(onDiskHand); HNoPurge(onDiskHand); } } } -- Eric K. Olson, Editor, Prepare() NOTE: olson@bootsie.uucp doesn't work Lexington Software Design Internet: olson@endor.harvard.edu 72A Lowell St., Lexington, MA 02173 Uucp: harvard!endor!olson (617) 863-9624 Bitnet: OLSON@HARVARD
lsr@Apple.COM (Larry Rosenstein) (02/19/91)
In article <1CE00001.ed5n0r@tbomb.ice.com> time@ice.com writes: > > if (*resHand!=NULL) { /* The resource was loaded */ > DetatchResource(resHand); > onDiskHand = GetResource(type, id); > DetachResource(onDiskHand); > /* Now move that resource back into place... */ > onDiskHand2 = GetResource(type, id); > SizeResource(onDiskHand2, GetHandleSize(resHand)); > BlockMove(*resHand, *onDiskHand2, GetHandleSize(resHand)); > ChangedResource(resHand); > } I think you may have mis-typed something here. It doesn't make much sense to call ChangedResource with something that's been detached (resHand). Anyway, a more fundamental problem is that the "current" handle to the resource is onDiskHand2, not resHand. It's possible that some piece of code was using resHand, and that code will be screwed. You have to do this without calling DetachResource. One way that comes to mind is: if (*resHand != NULL) { /* save current contents */ oldSize = GetHandleSize(resHand); save = NewHandle(oldSize); BlockMove(*resHand, *save, oldSize); EmptyHandle(resHand); LoadResource(resHand); /* re-load disk copy */ diskCopy = resHand; HandToHand(diskCopy); /* make a copy of it */ /* restore original version */ SetHandleSize(resHand, oldSize); BlockMove(*save, *resHand, oldSize); DisposHandle(save); } -- Larry Rosenstein, Object Specialist Apple Computer, Inc. 20525 Mariani Ave, MS 3-PK Cupertino, CA 95014 AppleLink:Rosenstein1 domain:lsr@Apple.COM UUCP:{sun,voder,nsc,decwrl}!apple!lsr
olson@bootsie.uucp (Eric K. Olson) (02/20/91)
In a recent article, Larry Rosenstein (lsr@Apple.COM) writes: >[Re: Reading data from disk while resource in memory] > > You have to do this without calling DetachResource. > One way that comes to mind is: > >if (*resHand != NULL) { > /* save current contents */ > oldSize = GetHandleSize(resHand); > save = NewHandle(oldSize); > BlockMove(*resHand, *save, oldSize); > > EmptyHandle(resHand); > LoadResource(resHand); /* re-load disk copy */ > > diskCopy = resHand; > HandToHand(diskCopy); /* make a copy of it */ ^^^^^^^^ HandToHand(&diskCopy); > > /* restore original version */ > SetHandleSize(resHand, oldSize); > BlockMove(*save, *resHand, oldSize); > DisposHandle(save); > } > This code is more like what I was looking for. I definitely prefer this to the rule-breaking solution I posted earlier. I've tried it (with the fix to HandToHand()) and it seems to work fine. Thanks Again, Larry! It's worth noting that in THINK C (and probably MPW), the call to HandToHand() in the included code below should be: HandToHand(&diskCopy); It occurs to me that calling DetachResource() on _any_ resource in the currently running Application could be dangerous (if that resource has been GetResource()'ed by some other part of your program). It might help to think of my application as a parasitic FKEY resource editor (it's not-- it's the Prepare() View Editor) that can't really know what resources are in use by the host application. (Similarly, the View Editor is intended to work compiled into any other application, whose objects may be using resources). Is it possible to know what resources have been gotten and have since been purged? Or gotten with SetResLoad(FALSE)? You can't call DetachResource() on those, either, I presume, although you can HandToHand() it and return the copy, then EmptyHandle() the resource handle if it was empty before. Or I could call HPurge() on the resource handle (if it was empty before), so it might remain in memory until the next time it's GetResource()'ed. Is this kosher? /* Detach a resource, leaving previous references around */ Handle MyDetachResource(Handle aResHandle, Boolean wasLoaded) { Handle aDataHandle; aDataHandle = aResHandle; HandToHand(&aResHandle); if (!wasLoaded) { HPurge(aResHandle); OR EmptyHandle(aResHandle); } return aDataHandle; } -Eric -- Eric K. Olson, Editor, Prepare() NOTE: olson@bootsie.uucp doesn't work Lexington Software Design Internet: olson@endor.harvard.edu 72A Lowell St., Lexington, MA 02173 Uucp: harvard!endor!olson (617) 863-9624 Bitnet: OLSON@HARVARD
lsr@Apple.com (Larry Rosenstein) (02/22/91)
In article <1991Feb20.101151.22358@bootsie.uucp>, olson@bootsie.uucp (Eric K. Olson) writes: > > It occurs to me that calling DetachResource() on _any_ resource in the > currently running Application could be dangerous (if that resource has > been GetResource()'ed by some other part of your program). It might You also have to be careful about system resources (for example snds), because these are shared under MultiFinder. > Is it possible to know what resources have been gotten and have since > been purged? Or gotten with SetResLoad(FALSE)? I think you would have to walk through the resource map, because that's where the handle would be stored if it has been gotten. Larry