The management of memory for resources in 16-bit Windows, redux

Some time ago, I briefly ran down how 16-bit Windows managed memory for resources. But there's a detail that I neglected to mention: Ownership.

As we saw, a resource handle HRSRC was really a pointer to the resource directory entry of the resource from the corresponding module. This could be done with a 16-bit pointer because the segment portion of the pointer could be inferred from the module the resource belonged to. In fact, since modules could be relocated in memory at run time due to compaction, you had better not try to remember the segment portion of the pointer since it could change!

The Find­Resource function located the resource directory entry. The Load­Resource function allocated memory for the resource and loaded it from disk. The Lock­Resource function locked the memory so you could access it. If two people tried to load the same resource, the memory for the resource was re-used so there was only one copy in memory, and if both people free the resource, the resource is cached in case somebody asks for it again soon.

Now things get interesting: When does the resource get removed from the cache? What actually controls the lifetime of the resource?

Answer: The resource lifetime is tied to the module it came from. When the module is unloaded, all its resources are unloaded along with it. (Note that even if a resource is cached, its contents can get discarded if it is tagged as DISCARDABLE.)

In Win32, modules are directly mapped into memory, and along with it, the resources. Therefore, accessing the resources of a module is a simple matter of figuring out where they got mapped (Find­Resource and friends will tell you), and then reading the memory directly. So despite the radical change to resources work, the basic rules haven't changed: The resources are good as long as the module is still in memory.

But there are resources and then there are resources. So far, we've been talking about resources in the sense of Find­Resource, which I will call module resources for lack of a better term. But people often work with objects like icons and bitmaps which are not literally resources but which are derived from resources. Next time, we'll look at the relationship between module resources and resource-derived objects in 16-bit Windows.

Comments (10)
  1. Joshua says:

    It occurred to me awhile back that anybody who designed a system in 16 bit Windows that depended on the DATA segment of a DLL being shared by all processes that loaded that DLL would be in a world of hurt in porting to 32 bit Windows.

    [Actually, it worked out mostly okay. Each DLL thinks that it is being used by only one process in the system. -Raymond]
  2. Joshua says:

    [Actually, it worked out mostly okay. Each DLL thinks that it is being used by only one process in the system. -Raymond]

    Not if two processes were using the shared DLL for shared state.

    [Each DLL then thought that it was being used by only one process. The other process using the DLL was invisible. (It was running in another VM, you might say.) The shared state was not shared because there was nobody to share it with. In general, this worked out okay. -Raymond]
  3. Neil says:

    And in 32-bit land, hPrevInstance was always NULL. Each process then thought that it was the first instance. In general, this worked out okay.

  4. GregM says:

    Raymond, I think Joshua was just saying that anyone that depended on the sharing to happen would have to completely replace that way of communicating when porting to Win32, not that something bad would happen when the programs ran.  So the world of hurt is during development, not at runtime.

  5. laonianren says:

    @GregM: Win32 supports shared data sections in DLLs, so you wouldn't have to completely replace the functionality.  Of course, that creates a synchronisation problem, but you could probably fix that by attaching the input of your processes.

  6. Deduplicator says:


    You know that's not a "Get out of Jail" but a "Let's merge those Jails (so noone feels responsible for anything)" card?

    Raymond had a few posts about the evils of attached Input queues. The treatment is worse than the disease.

    Just accept you have to redesign your IPC.

    "In general, this worked out okay." That's true, in general, this feature was not used, though sometimes it might be used as a shortcut, and the few remaining cases can be ignored.

  7. Chris says:

    I've just spent two months remediating a suite of 16-bit programs that massively shared data using DLLs between programs.  Pointers to blocks of storage were shared in INI files so that small VB3 programs could be used as common dialogs to other VB3 programs.  It's been a journey as they say, mostly solved by using an ActiveX singleton EXE.

  8. laonianren says:

    @Deduplicator: We're talking about porting 16-bit apps, so they already expect to have their input queues attached.  This isn't a great long-term solution, but sometimes a legitimate goal is to get your app ported as quickly as possible.

  9. Joshua says:

    @Chris: Wow, somebody actually *did* it. I saw a database engine proposed that way sooo many years ago but I never thought one would see the light of day.

  10. It sort of happened.  An object oriented data framework was written in C, nicely supporting aggregation, inheritance and implementation hiding.  The handles to the objects were returned to the caller (VB3 typically) as longs which were actually pointers to the meta-data for the object instance.  One of the teams using the framework noticed this and then used it as an IPC mechanism.  For VB3 on old Win 3.1. machines it probably worked well as it avoided costly refresh trips to the mainframe (through HLLAPI back then).

Comments are closed.