chaffee@uvm-gen.UUCP (Alex D. Chaffee,231 Votey,,6581273) (07/19/89)
I am writing a utility, called Valet, whose purpose in life is to move resources from one file to another. With the exception of one small flaw, it is ready to be posted into the public domain. This flaw concerns the system file: I "pack" a resource from another file into the (open) System file. Using my "Get info" command assures me that it is intact. I quit the program and immediately restart it. I open the System file again, do a get info, and bang! The resource is corrupt. The name and ID are fine, but SizeResource() returns -113. Yes, negative 113, or -111, or some arbitrarily huge number. ResEdit doesn't like it either. But if I open ResEdit after "packing" but before quitting (I'm using MultiFinder) and open the resource, it looks fine; then if I quit both and rerun Valet, _the resource _is_ fine_. Apparently ResEdit knows how to save the resource, but I don't. This only happens under MultiFinder. Under Finder, packing, quitting and restarting works perfectly. Before I order the Programmer's Guide to MultiFinder (which I somehow doubt would be much help, since I have done nothing even remotely sneaky or Finder-dependent), could someone tell me what, if anything, I can do to ensure that a resource I write to the system file stays healthy? The Fine Print: I am using a Mac SE, 2.5 megs, LightspeedC C v3.0. The problem occurs with or without the symbolic debugger, and from a standalone app; under Finder, it works when Run or launched. I have trashed and rebuilt my project, reinstalled LSC, reinstalled the System (dozens of times :-), and run under an INIT-free system. The program flow of "Packing" consists of: SetResLoad(FALSE); UseResFile(fileToPack); count = Count1Resources(type); for (i = 1; i <= count; ++i) { Hand = Get1IndResource(type, i); /* read the next resource */ [error checking] [ add resource data to an internal data structure ] } SetResLoad(TRUE); for ( [every resource] ) { [check if it exists] UseResFile(fileToPack); SetResLoad(TRUE); LoadResource(theItem->H); if (ResError()) ... DetachResource(theItem->H); if (ResError()) ... HNoPurge(theItem->H); UseResFile(masterFile); AddResource(theItem->H, theItem->species, newID, newName); if (ResError()) ... WriteResource(theItem->H); if (ResError()) ... } [erase internal data structure, without touching the resource handles] CloseResFile(fileToPack); UpdateResFile(masterFile); "Quitting" is: if ([the system file is open]) UpdateResFile(...); else CloseResFile(...); [dispose of all data -- but don't touch the resource handles] I have avoided (I believe) all the obvious pitfalls, like calling CloseResFile on the system file. I have error-checked beyond the limits of sanity. And IT WORKS UNDER UNIFINDER. Please, somebody... help... Alex Chaffee chaffee@emily.uvm.edu ____________________________
tim@hoptoad.uucp (Tim Maroney) (07/20/89)
Yum, this was a meaty one. In article <1230@uvm-gen.UUCP> chaffee@uvm-gen.UUCP (Alex D. Chaffee,231 Votey,,6581273) writes: >I "pack" a resource from another file into the (open) System file. Using my >"Get info" command assures me that it is intact. I quit the program and >immediately restart it. I open the System file again, do a get info, and >bang! The resource is corrupt. The name and ID are fine, but >SizeResource() returns -113. Yes, negative 113, or -111, or some >arbitrarily huge number. ResEdit doesn't like it either. But if I open >ResEdit after "packing" but before quitting (I'm using MultiFinder) and open >the resource, it looks fine; then if I quit both and rerun Valet, _the >resource _is_ fine_. Apparently ResEdit knows how to save the resource, but >I don't. > >This only happens under MultiFinder. Under Finder, packing, quitting and >restarting works perfectly. First, I want to thank you for describing your system configuration and development system, an important step that most people omit. >The program flow of "Packing" consists of: >for ( [every resource] ) >{ [check if it exists] > UseResFile(fileToPack); > SetResLoad(TRUE); > LoadResource(theItem->H); if (ResError()) ... > DetachResource(theItem->H); if (ResError()) ... > HNoPurge(theItem->H); > UseResFile(masterFile); > AddResource(theItem->H, theItem->species, newID, newName); > if (ResError()) ... > WriteResource(theItem->H); if (ResError()) ... >} >[erase internal data structure, without touching the resource handles] >CloseResFile(fileToPack); >UpdateResFile(masterFile); OK, I think I see the problem. Do a ReleaseResource after the WriteResource. What seems to be happening is that under MultiFinder, ExitToShell is not releasing application-specific copies of the system file resources. Therefore, when you quit, the resources are trashed, being in an invalid heap. (Actually, the trashing probably happens the next time you launch a program.) Since you have already done the WriteResource, there should not be a problem from the ReleaseResource, and it should cause the resource to be re-fetched from the system file when someone else wants to use it. ExitToShell *should* be releasing application-heap copies of the system file resources under MultiFinder. I know it does under UniFinder. However, if you think about it, there must be some sort of weird special casing involved. There's a dearth of internal information on MultiFinder, but a little poking with MacsBug reveals that different applications each have their own copy of the system resource map. So one would think that changes made to the system file from one application would invalidate other maps, and they'd have to be automatically refreshed somehow. If they weren't refreshed, their file indices would be bad, for one thing. So suppose this refreshing happens on your AddResource or WriteResource -- then when the other maps get refreshed, something has to fill in the new resource slots in their resource maps. If this is just the copy of the resource in your application heap, then everybody gets a handle into your app. heap inserted in their system resource map. When that heap dies, then their copies are trashed. ReleaseResource might work if it goes and changes everyone's copy, but not otherwise. I notice that if you close the window with ResEdit, then the resource saves OK -- note that ResEdit does do a ReleaseResource when it closes a resource window, so that would seem to indicate that doing your own ReleaseResource will do the trick. This is all out in outer space as far as degree of speculation goes, but it seems to be consistent with your symptoms. The upshot seems to be that you shouldn't make any changes to the system resource file from your application, because the undocumented nature of all this stuff makes whatever you do likely to break. There's no really good reason for anyone but the Font/DA Mover and ResEdit to make system file changes, so why don't you just have Valet refuse to mess with the system file? PS. Your AddResource will add a duplicate if the resource already exists in the target file. You should check for its existence first, then remove it if it exists. (You could also resize it and copy the source resource into the resized handle, but that wouldn't fit the way you've coded this very well.) -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com "Everything that gives us pleasure gives us pain to measure it by." -- The Residents, GOD IN THREE PERSONS
brecher@well.UUCP (Steve Brecher) (07/22/89)
In article <8065@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes: > ExitToShell *should* be releasing application-heap copies of the system > file resources under MultiFinder. I know it does under UniFinder. > However, if you think about it, there must be some sort of weird > special casing involved. There's a dearth of internal information on > MultiFinder, but a little poking with MacsBug reveals that different > applications each have their own copy of the system resource map. Application heap handles are removed from the System map by RsrcZoneInit, which is called during the launch process under uniFinder but not called under MultiFinder. There is only one copy of the System map. Each layer has its own resource map chain (TopMapHndl is switched), but each chain links to the System map in the system heap. [Tim's diagnosis (not quoted) of the original problem was correct, i.e., adding application heap handles to the System map under MultiFinder and then quitting without releasing the resources leaves dangling handles in the System map.] -- brecher@well.UUCP (Steve Brecher)
tim@hoptoad.uucp (Tim Maroney) (07/23/89)
In article <8065@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes: > ExitToShell *should* be releasing application-heap copies of the system > file resources under MultiFinder. I know it does under UniFinder. > However, if you think about it, there must be some sort of weird > special casing involved. There's a dearth of internal information on > MultiFinder, but a little poking with MacsBug reveals that different > applications each have their own copy of the system resource map. In article <12810@well.UUCP> brecher@well.UUCP (Steve Brecher) writes: >Application heap handles are removed from the System map by RsrcZoneInit, >which is called during the launch process under uniFinder but not called >under MultiFinder. That's correct, but there must be some analogous call which is made under MultiFinder. Otherwise, copies of resources in the system map that appeared in the application heap of one application would be trashed when the next application ran. (Good guess, but false -- see below.) >There is only one copy of the System map. Each layer has its own resource >map chain (TopMapHndl is switched), but each chain links to the System map >in the system heap. You're right, I was wrong. I was looking at SysMap and thinking it was the handle; in fact, SysMapHndl is the handle. The illusory four-byte SysMap changed every time because the second word is actually another low-memory global, which is switched. Sigh. >[Tim's diagnosis (not quoted) of the original problem was correct, i.e., >adding application heap handles to the System map under MultiFinder and >then quitting without releasing the resources leaves dangling handles in >the System map.] Yes. I'm just wondering why there's a difference between adding resources to the map and just accessing them. They must be thrown away somehow if they're in the application heap; when the system decides to throw them away, what's the difference between one that's been added recently and one that hasn't? The only way I can see that they would *not* have to be thrown away would be if they were not ordinarily read into the application heap. I've just done a bit more probing with MacsBug, using the HD command, and I can't find any resources in any application heaps that claim to be from resource file 2, which is the reference number of the system file. In fact, when I check DA Handler with a DA open, whose resources you would think would be in the DA Handler application heap, there are no resources except from the DA Handler resource file. So perhaps under MultiFinder all resources in the system file are read into the system heap whether they have the system heap bit set or not. I just looked at the system heap with MacsBug and there are indeed a number of resources there from file 2 which, when examined by ResEdit, do not have the system heap bit set. So that would appear to be the answer. So, the original questioner could do a ReleaseResource as I suggested, but a better approach would be to allocate the resource storage in the system heap before adding it to the system file. Then the ReleaseResource becomes unneccessary. Thanks for the corrections. They've spurred me on to a better understanding of MultiFinder. -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com "Americans will buy anything, as long as it doesn't cross the thin line between cute and demonic." -- Ian Shoales
chaffee@uvm-gen.UUCP (Alex D. Chaffee,,,6581273) (07/25/89)
Tim Maroney (tim@hoptoad.uucp) writes: >Yes. I'm just wondering why there's a difference between adding >resources to the map and just accessing them. They must be thrown away >somehow if they're in the application heap; when the system decides to >throw them away, what's the difference between one that's been added >recently and one that hasn't? Actually, the difference is that the added handle pointed to data that was in the application heap. Remember, I was loading a resource from another file, detaching it, and then adding it to the system file. When the application quit, this heap was no longer valid, but the handle remained. >So, the original questioner could do a ReleaseResource as I suggested, >but a better approach would be to allocate the resource storage in the >system heap before adding it to the system file. Then the >ReleaseResource becomes unneccessary. This is impractical. I would either have to copy the resource between the heaps, requiring twice as much memory, or do some pre-load mucking with the resource map to set the System Heap bit on, which sounds more dangerous than just releasing the resource once IUm through with it. MultiFinder will load it into the system heap the next time anyone wants it anyway. jerryg@Apple.COM (Jerry Godes) quotes Tech Note 180: MultiFinder Miscellanea [Confirms that MultiFinder loads all system resources into the system heap.] I was wrong; it is documented. Yet my original gripe with this scheme still stands. Isn't MultiFinder supposed to be transparent to programs which don't make use of it? I know, I know... "And the Congress is supposed to represent the people... and comic strips aren't supposed to end..." "Gilda Radner isn't supposed to end." "Probably the Government's fault." __________________________ Bloom County Alex Chaffee chaffee@emily.uvm.edu ____________________________
brecher@well.UUCP (Steve Brecher) (07/26/89)
In article <8102@hoptoad.uucp>, tim@hoptoad.uucp (Tim Maroney) writes: > So perhaps under MultiFinder all resources in the system file are read > into the system heap whether they have the system heap bit set or not. Correct. This applies also to resources in suitcase files opened with Suitcase II. > So, the original questioner could do a ReleaseResource as I suggested, > but a better approach would be to allocate the resource storage in the > system heap before adding it to the system file. Then the > ReleaseResource becomes unneccessary. Allocating the resource storage in the system heap would have avoided the dangling-handle problem even if ReleaseResource were not called. But omitting ReleaseResource would introduce another problem: heap clogging. If not ReleaseResource, then HPurge would be required to avoid possible heap overflow. Further, one has better control over application heap management than system heap management, so I think that the original approach, with ReleaseResource added, is the best solution. -- brecher@well.UUCP (Steve Brecher)