Content-Length: 7664 Content-Type: text/html
Some of the most obvious missing pieces of information in the OS/2 documentation is related to the use of resources and resource ids, and the possible schemes for managing them. Each OS/2 resource has a type (defined by the RT_xxxx values in BSEDOS.H) and an id. When you watch the resource compiler putting out numbers like 3:100, that means a menu (RT_MENU is 3) with the id 100.
The type and id values are used to extract the resource from a particular DLL or EXE module, using the DosGetResource() API. You might never use DosGetResource() yourself, but that is the underlying API that extracts a resource into a system allocated memory buffer. A program does not have to be a WINDOWAPI program to access resources in this way because the actual resource is not created, just the description of it is loaded.
The Resource Id 'Name Space'
Since you must access a resource by providing the module handle of the DLL or EXE module that it is attached to, there is effectively a 'resource name space' with three levels. So a particular resource has a 'path' like this:
\HModule\RT_xxxx\Id
This means, though it never seems to be pointed out, that the type:id pairs are automatically unique within each DLL or EXE module. So, for instance, you can have a bitmap with an id of 1 in every single Dll in a program and there will be no problem with id conflict. There can also be a bitmap and a string and a dialog with the id of 1 within a particular DLL or EXE. This is particularly convenient ("Nay, absolutely required," he said in a regal manner), when building black box DLLs for distribution or doing large, multiple group development. You just don't have to worry about resource id distribution except within a particular DLL or EXE module.
Resource Access APIs
You will generally access resources via a set of higher level (read PM oriented) APIs which themselves use DosGetResource() to load up the raw resource description. These APIs then use that description to build the actual PM resource, after which they can discard the raw buffer. WinLoadString(), WinLoadDlg(), WinLoadPointer(), etc. are examples of these convenience resource APIs. You could easily (relatively speaking of course) replace these APIs with your own and enhance or expand on them, because they are not magical in any way and have no privileged knowledge or system access. The format of the raw buffer is, as far as I know, the exact format from the .RES file that was attached to the DLL or EXE. Finding the details of that format for some of the resource types is though sometimes like drawing blood from a stone.
For instance, in my class libraries, I wanted to have a strict separation between GUI and non-GUI code but wanted to have string resources accessible in the lowest level (kernel encapsulation) DLL. So I provided my own methods to extract string resources. Tehnically I could probably call WinLoadString() with a 0 HAB, but I did not want to cheat. Its quite simple and you can do things like cache the most recently accessed strings for fast access (if that makes sense for your access patterns.) String resources are actually grouped in sets of 16, called string tables, so you extract them in these tables and pull out the particular one of interest. So caching this table is the most convenient way to keep them in memory. This also makes it most efficient to group your strings (if they are not all just consecutively numbered) so that they start on ids which are multiples of 16.
While I'm spending your development dollars here, another good use of this technique is in a scalable interface. Lets say you wanted to provide a 4 level interface (from expert down to severely challenged, for me), you could arrange your string ids such that each 'message' started on a multiple of 16. But a 'mes sage' would actually be 4 strings at successive ids starting from the first one. The program itself would just ask to load the 'message id' which would be the id of the first string in each group. The loading function would pull in the string table for that 'message' and then use the program's current interface level to return the actual string for that level. Having the base id for each message an even multiple of 16 insures that all of its related messages are in the same string table and loaded together.
I also use DosGetResource() to load up dialog definition resource buffers and use that template to create my own dialog windows. This gives me more control. See Dialogs As Main Windows above.
Copyright Notice
| Reply to Author
| Search
| Section Index
| Previous Page
| Next Page
If you see a problem with this web site, contact
edm2_eds@iqpac.com.