Re: Proper use of #getImageBlock in runtime [LONG!]



Sebastián,

actually I'm trying to locate resources in an uniform way in runtime
and development, so I'll take a look at ResourceLocator. If you has
some advice to this regard please tell me.

BTW: I misnamed the locators; they are "FileLocators" not "ResourceLocators".
Sorry if that confused anyone.

This is an attempt to collect together what I know about resource location in
Dolphin. It may be more than you want to read ;-) OTOH, it repeats stuff that
I've said before in other posts, so it may be more than anyone else wants to
read either...

Another warning: this is all based on D5; I haven't looked to see what has
changed in this area in D6 (I know there are at least a couple of
enhancements).

======================

*** Some Background: ***

When Dolphin reads an icon or bitmap, there are two fundamentally different
ways it can do it (corresponding to two fundamentally different Windows
features). It can load it from a "resource" embedded in an executable file
(such as the current executable or some DLL), or it can load it from a file.

One way to create an Icon is from a .ICO file, using by an expression like:
Icon fromFile: 'filename.ico' usingLocator: aFileLocator.
where the FileLocator is an instance of one of the subclasses of FileLocator
whose job is to turn a "relative" filename into something that the Window's OS
can actually open. (More on FileLocators below.)

A slightly simpler form of the above is:
Icon fromFile: 'filename.ico'.
which is just the same except that it will use the default locator (which is an
ImageRelativeFileLocator).

(As an aside: when you look at an Icon (or whatever) in the VC, the information
coming from the Icon>>printOn: is misleading. it /looks/ like a valid Icon
creation expression (indeed it is valid -- just wrong), but the expression
doesn't reflect the FileLocator that is actually in use. What's more the
standard FileLocators don't have useful implementations of #printOn: either.)

The alternative method of loading icons is from the resources compiled into a
DLL (or .EXE). Here the fully general creation expression is something like:
Icon fromId: 134 in: ShellLibrary default.
Here you give an "id" which can be either a String or an Integer to find the
correspondingly named icon resource in an instance of ExternalLibrary.
ExternalLibraries are normally used for wrapping access to another DLL's code,
not merely for loading icons, and you may well want to load icons from some
arbitrary DLL (or .EXE) that doesn't already have a corresponding
ExternalLibrary subclass. The special subclass ExternalResourceLibrary is
intended to cover that case. You can say things like:

notepad := ExternalResourceLibrary open: 'C:\Windows\system32\notepad.exe'.
icon := Icon fromId: 2 in: notepad.
notepad close.

A couple of special cases. One is that if you miss off the library:
Icon fromId: 428.
or:
Icon fromId: 'ASPECTBUFFER.ICO'.
then Dolphin will look in the current SessionManager's #defaultResLibPath. By
default that just points to the DolphinDR005.DLL resource DLL -- which isn't
much use for deployed .exes unless you also ship that DLL with your
application. It's normal to override that method to answer something like:

defaultResLibPath
^ self imageFileName.

in your applications' custom SessionManagers.

A second special case is that you can provide nil as the ResourceLibrary, which
is interpreted (by Windows) as a request to load resources from the current
application's .exe. E.g:
Icon fromId: '!APPLICATION' in: nil
finds the application's "main" icon.

I said above that there are "two fundamentally different ways" of loading an
Icon. Actually Dolphin tries hard to merge them. The way it works is this:
when you create an Icon with:
Icon fromFile: 'filename.ico' usingLocator: aFileLocator.
or
Icon fromId: 'ASPECTBUFFER.ICO' in: anExternalLibrary
the name part ('filename.ico' or 'ASPECTBUFFER.ICO') is stored in the Icon
object as its #identifier. When Dolphin tries to load the data for that icon,
it will attempt to use the #identifier with the corresponding Windows API to
load the data from the requested place (file or DLL). If that fails, then it
falls back to attempting to use the #identifier to load the data from the
#defaultResLibPath. That (combined with the above override of
#defaultResLibPath) can be very handy, because it means that you can (if you do
it right) make Dolphin look for icons in external files in a development image,
but look for Windows "resources" bound into the .EXE when deployed (more
of this below).


*** FileLocators ***

Now, onto how FileLocators really fit into this picture, and some ideas about
how they can be used. (We'll forget about resources in DLLs and EXEs for a
minute -- I'll come back to that later.)

When you create an Icon (or similar) the Icon instance stores the supplied
filename in its #identifier, and also the FileLocator that you supplied (or the
system default if you didn't supply one). When the image data for that Icon is
needed, the FileLocator is used to convert the #identifier into a filename.
The image data itself is not stored when Dolphin is closed down, just the
information needed to reload it. That applies to deployed executables too, so
the key to using Icons in deployed executables is to ensure that the Icon
instances (whether stored inside "view resources" which you created with the
VC, or created on the fly) have FileLocators which will be able to find the
file corresponding to the #identifier when Dolphin (or the deployed exe) starts
up.

The simplest (but worst ;-) way is to use the absolute filename as the
#identifier.
Icon fromFile: 'C:\My Stuff\My Icons\filename.ico'
FileLocators treat absolute pathnames specially, and don't try to resolve
them. So that Icon will always look for its data in that file.

The next simplest, is to use an ImageRelativeFileLocator (which, you may
remember, is the default).
Icon fromFile: 'filename.ico'.
or
Icon fromFile: 'filename.ico' usingLocator FileLocator default.
or even:
Icon
fromFile: 'filename.ico'
usingLocator: ImageRelativeFileLocator current.
An ImageRelativeFileLocator (or rather, /the/ ImageRelativeFileLocator since
its a Singleton) looks up Icons' #identifiers relative to the current image
(which is the executable itself when deployed). So the above Icon would look
for 'filename.ico' in the same directory as your development image, and at
runtime would look in the same directory as your application.

I prefer to put icons and such into a special 'Resources\' sub-directory, so we
can elaborate that a little:
Icon fromFile: 'Resources\filename.ico'.
which will look in the Resources subdirectory of the place where your
development image lives, or in the Resources subdirectory of where the
application lives.

Now let's get a little more elaborate still. I don't like putting my icons in
the same folder as my image (or even in a sub-directory of it). I want to put
the icons with the package that uses them. So this is where we get creative
and define a custom FileLocator that understands /my/ way of doing things.
We can define a PackageRelativeFileLocator which includes the name of a package
as part of its definition. When it is asked to resolve:
'filename.ico'
it first checks to see if it's in a development image. If it is, then it finds
package with that name, asks the Package where it lives, and then resolves the
filename relative to that. In a deployed executable it acts just like an
ImageRelativeFileLocator.
Icon
fromFile: 'filename.ico'
usingLocator: (PackageRelativeFileLocator packageNamed: 'MyStuff.pac')
I have an implementation of that on my website, and a (slightly earlier)
version of it is included as standard in D6.

As before we can use a Resources\ sub-directory if we wish:
Icon
fromFile: 'Resources\filename.ico'
usingLocator: (PackageRelativeFileLocator packageNamed: 'MyStuff.pac')


*** Bound Resources ***

That's pretty flexible, but we can go one or two steps further if we want.

Next we have the option of binding icon files (etc) into the .exe itself as
Windows "resources". To do that you use a resource editor such as
"ResWhacker", "XN Resource Editor" or MS's Visual Studio (the editor in VC 6 is
better than the one in VS 2003). You edit your executable to add the icon as a
resource. Give the resource a name like:
"FILENAME.ICO"
(It has to be all upper-case or the lookup will fail at runtime!) which is the
same as the Icon's #identifier. In D6 you can do that after the executable has
been deployed. In D5 you have to edit the stub .EXE /before/ you deploy. Once
you have done that (as I described above), the Dolphin runtime will find the
data in the executable itself if it can't find it via the icon's FileLocator.

But now we hit a snag. If we're using a Resources\ subdirectory, then the
Icon's #identifier will be:
'Resources\filename.ico'
and so we'd like to be able to use that (in upper-case, of course) as the name
of the resource bound into the .EXE. Problem is that doesn't work -- Windows
lets you /define/ a resource with that name (if I remember correctly) but it
can't find it at runtime.

So now for the last step in this over-long description. One way to fix this
problem would be to change the various definitions of #loadFromInstance: so
that they stripped off the directory part of any resource name before handing
it to Windows. That might work, but I prefer to use a different approach.
Enter my culminating custom FileLocator <drum roll>...

PackageResourceLocator !!!

This is very similar to a PackageRelativeFileLocator except that it also holds
the name of a sub-directory ('Resources/' by default), where it "knows" that
resources are kept.
Icon
fromFile: 'filename.ico'
usingLocator: (PackageResourceLocator packageNamed: 'MyStuff.pac')
This will automatically look in the Resources sub-directory of the image or
package directory. And, since the Icon's #identifier is just 'filename.ico',
Windows will be also able to find it in the executable (if it's there).

That's also in package 'CU Package-relative File Locator' package on my website
(under Miscellanea) if you're interested.

I've described my own custom FileLocators -- they are useful for me, and maybe
they'll be useful to other people too -- but the important point is that by
defining your own FileLocators you can make Dolphin work /your/ way.

======================

That's it. Whew....

-- chris


.



Relevant Pages

  • HLA v2.x and / or LASM suggestion: Win32 Resources
    ... With Microsoft's RC compiler, I've just noticed that it's less capable ... binary resource converted into readable, ... possible to create an icon or bitmap on-the-fly in the actual program ... make a separate tool and then all of them can share ...
    (alt.lang.asm)
  • Re: Single use of ICON in all forms
    ... > "Icon", but the Icon class does not have a FromStreammethod. ... > "Matt Berther" wrote in message ... >> Embedding the file as a resource is no big deal... ... Embedding it as a resource would still leave me with two ...
    (microsoft.public.dotnet.framework.windowsforms)
  • Re: Application icon
    ... Regards ... > this, you can create a resource compiler script file for the icon, and ... > create a resource file by using the Rc.exe utility. ... use the following code to create a resource compiler script ...
    (microsoft.public.dotnet.vjsharp)
  • Re: Animating Tray Icon using Shell_NotifyIcon
    ... > The resource file bears the same name as the .dll, ... The Delphi IDE allows you configure an icon for your project and also ... More importantly, Delphi ... sorted ahead of MAINICON. ...
    (alt.comp.lang.borland-delphi)
  • Re: Icon in a run-time package
    ... > Is there a way to add an icon to a run-time package, ... the resource file to your project using a statement. ...
    (borland.public.delphi.language.objectpascal)

Loading