FB II Compiler
Master the Resource Manager
I have been working on a project for the last few months. It has an external resource file and to make sure that I don't get a collision, I open the external resource file, use the toolbox USERESREF(filenumb) to switch to it and then extract my resource using GET1RESOURCE (again from the toolbox).
While this works 98% of time, I have a number of clients who crash at exactly the same point each time. What works flawlessly here in the office and for some flatly refuses to work for others. Or is hit and miss.
I've re-written my routines several different ways and mostly to no avail. I was reading a muse from a fellow programmer this morning and it shed a little light...and just maybe a logical reason.
"I've heard from six different users who tell me that Surf Express 1.1.1 causes my programs (Window Monkey, Helium and Holiday Lights) to fail to work . Specifically, when opening the Window Monkey or Helium control panels, or the Holiday Lights application, users see a message saying that an "unexpected error occurred." With the help of one of these users, I have narrowed down the exact line of code that fails in my programs. It's in the resource-manager related toolbox call 'Get1IndResource.' In my case, it looks like this: Get1IndResource ('MCmd', 1). What this does is try to load the first 'MCmd' resource in the current resource file (which should be the control panel or application file). With Surf Express installed, this toolbox call fails and the resource is not loaded, which should never happen; hence the "unexpected error" message. Either Surf Express is changing the current resource file (very bad), or it installs a trap patch that causes Get1IndResource to fail in certain (perhaps all) situations. Get1IndResource is not a very commonly used resource manager call, but it's used often enough that I can see how this bug could cause other problems. For example, Navigator could fail to load the animated icon resources."
Myself, I am not using the Get1IndResource as the other author is, but I am using a subset of it "GET1RESOURCE". I know that GETRESOURCE always works so here's the question of day for those who know.
If you call USERESREF and then a GETRESOURCE, it should work exactly the same as GET1RESOURCE? Or is there a risk of it falling down through the open resource files and finding a match that is NOT in the external resource file I am using? Or any way to tell?
Secondly, when you read in a resource from an external file, and then close the external file, is the handle still valid in memory or does closing the external file remove all references to anything it might have contained? All my external resources are marked purgeable so maybe the memory manager is doing what it's supposed to do when you close an external resource file.
Ultimately, the answer could be a system conflict with an extension or control panel. But try telling that to a client. They are always quick to point out, "Microsoft Word works"...;-)
The problem is that USERESREF changes the resource file list, which is a side effect that can cause problems. Never change the resource file list if you can possibly help it.
Instead, I'd recommend using a "passive" approach. Call GETRESOURCE and let the system load whatever resource it wants to. Then use FN HOMERESFILE to get the file number the just-loaded resource comes from. If it's not your file, ignore it.
Another way to avoid conflict might be something like this:
oldRes% = FN CURRESFILE
'..load the resource...
All resources are dumped when you close the resource file that owns them.To keep a resource handle around no matter what, use DETACHRESOURCE on the handle. This turns the resource handle into an ordinary handle, so it is no longer attached to the resource file.
GETRESOURCE always looks in the current resource file first. The only way it could "fall through" to other open resource files (such as your app's resource fork or the System resource file) would be if the resource you're looking for was actually not in the current resource file.
If you call "DetachResource" before you close the external file, then the handle will still be valid. Otherwise the Resource Manager disposes of the handle when you close the file.
By marking the resources purgeable, you're giving the Memory Manager permission to remove the blocks from memory at its own discretion (but not necessarily immediately). When you close the resource file, the blocks are removed immediately.
This brings up an interesting point--could it be that (in 2% of the cases) your resources are in fact being purged, and your program is not taking that into account? Whenever your program needs to directly examine or alter the contents of a purgeable resource, you should make sure that resource is actually still in memory (call LoadResource then Hlock the handle, if you have doubts).
What kind of error code does Get1Resource return?
Are you sure your user have read-access to the external file?