Proper use of #getImageBlock in runtime

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Proper use of #getImageBlock in runtime

Sebastián Sastre
Hi All,

  I want to know that is the idea for the use of List's #getImageBlock
in runtime.

 I understands that the block should return an icon index, but I can't
figure out how I should make a consistent managment of my resources
between the development and runtime.

 What is suposed to do to have an application locating the images in
runtime as in developent?

  thanks,

Sebastian


Reply | Threaded
Open this post in threaded view
|

Re: Proper use of #getImageBlock in runtime

Don Rylander-3
Sebastian,
"Sebastián" <[hidden email]> wrote in message
news:[hidden email]...
> Hi All,
>
>  I want to know that is the idea for the use of List's #getImageBlock
> in runtime.
>
> I understands that the block should return an icon index, but I can't
> figure out how I should make a consistent managment of my resources
> between the development and runtime.
The very simplest way is to refer to icon resources by the filenames.  Keep
copies of your icon files in the same directory as your development image.
When you deploy your application, you can either put the icon files in the
same directory as the executable file, or (before you deploy!) you can add
them as resources to the stub file the image stripper uses for deployment.

Whether this is also the best way is open to question, but it is simple.

Hope that helps,

Don

>
> What is suposed to do to have an application locating the images in
> runtime as in developent?
>
>  thanks,
>
> Sebastian
>


Reply | Threaded
Open this post in threaded view
|

Re: Proper use of #getImageBlock in runtime

Sebastián Sastre
Don,

 I'm already doing the GUIToGo resource edition to embed the resources
on the exe, and, as yu said, refering them by their names. What I want
to have is a consistent way to work between development and runtime.
Now, in development (and runtime) I'm also getting the icons of the by
their names or as toolbar with an index. What I dont get is the
#getImageBlock that wants an index (not being a toolbar). I'm trying to
understand the intention of the choice of location of the icons in this
way, so I can use it in the right way or customize to make it work in
my way.

Thanks,

Sebastian


Reply | Threaded
Open this post in threaded view
|

Re: Proper use of #getImageBlock in runtime

Don Rylander-3
Sebastian,
"Sebastián" <[hidden email]> wrote in message
news:[hidden email]...

> Don,
>
> I'm already doing the GUIToGo resource edition to embed the resources
> on the exe, and, as yu said, refering them by their names. What I want
> to have is a consistent way to work between development and runtime.
> Now, in development (and runtime) I'm also getting the icons of the by
> their names or as toolbar with an index. What I dont get is the
> #getImageBlock that wants an index (not being a toolbar). I'm trying to
> understand the intention of the choice of location of the icons in this
> way, so I can use it in the right way or customize to make it work in
> my way.
Did you know that you can just ask an icon for its imageIndex?  In a block,
you would put something like:

[:item| item mySpecialListIcon imageIndex ]

Or do I still misunderstand?  Sorry if I'm being obtuse.

Don

>
> Thanks,
>
> Sebastian
>


Reply | Threaded
Open this post in threaded view
|

Re: Proper use of #getImageBlock in runtime

Chris Uppal-3
In reply to this post by Sebastián Sastre
Sebastián wrote:

> What I want
> to have is a consistent way to work between development and runtime.
> Now, in development (and runtime) I'm also getting the icons of the by
> their names or as toolbar with an index. What I dont get is the
> #getImageBlock that wants an index (not being a toolbar). I'm trying to
> understand the intention of the choice of location of the icons in this
> way, so I can use it in the right way or customize to make it work in
> my way.

I'm not sure what you are asking here.

Is your question about how to locate icon (etc) files in a uniform way in both
a development environment and in a deployed application ? If so then you may
well find that a suitable ResourceLocator is the key.  There's quite a bit
about this question in the archives, or we can talk more about it here if you
like.

Or is your question about how to find a suitable icon /index/ ?  If so then I
don't think you need to bother about it.  Icons look after their own indexes,
so (as far as I know) there is never any reason to produce an image index that
doesn't come from sending #imageIndex to an actual Icon.  I don't really
understand why the #getImageBlock is expected to answer an index, it would make
much more sense (to my mind) if it just produced for an Icon.  (There is, BTW,
some very heavy caching of Icons in the system -- indeed the #imageIndex is
part of that, normally hidden, sub-system, it has nothing to do with anything
visible to a user).

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Proper use of #getImageBlock in runtime

Sebastián Sastre
Chris,

  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.

  In the other hand I also was mispointed (amplified by a little bug I
found just a minutes ago in my code) by the #getImageBlock expecting an
image index instead of an image. Perhaps calling that block
#getImageIndexBlock would be a happier alternative.

 thank you for the clarity,

 regards,

Sebastian


Reply | Threaded
Open this post in threaded view
|

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

Chris Uppal-3
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


Reply | Threaded
Open this post in threaded view
|

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

Don Rylander-3
Chris, this is a very useful summary.  Your Package*Locators are similar to
what I've wanted to do for a while (one of those low-priority items that
never reached escape velocity).  One problem for me was the desire to avoid
hard-coding the package name in a method; whether I've expended more effort
avoiding that remains an open question.

This does leave me wondering how difficult it would be to make it all
simpler for new users, though.  It seems like integrating your locator
classes with some means of binding packages' icons into the deployed image
could remove some annoying barriers.

It might be possible to utilize ResHacker's command-line features combined
with your package-relative stuff to create custom stubs at (or just before)
deployment time.  (ResHacker can easily do bulk loading of resources into
DLL and EXE files.  Of course, Dolphin will eventually have that capability
itself; I'm sure ImageStripper>>updateIconResource: is going to be done any
day now.  ;^)

I'm thinking of a process like: scan the package's dependencies, exclude the
OA packages, round up all the icon files in the packages' directories, write
a resource script for the icons, and compile them into a new stub with
ResHacker.

I think I might look at how hard it would be to come up with a rudimentary
first draft in the next week or so.  Then we just need some way to manage
resource files (icons, manifests, etc.) in STS...

Don


Reply | Threaded
Open this post in threaded view
|

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

Chris Uppal-3
Don,

>  One problem for me was the desire
> to avoid hard-coding the package name in a method; whether I've expended
> more effort avoiding that remains an open question.

What I do is use a class-side helper method like:

===========
    resourceLocator
         "private -- answer a FileLocator that will find files in our
        standard location for resources"

         ^ PackageResourceLocator packageNamed: ##(self owningPackageName).
===========

It does have to be recompiled if I move a class into another package or rename
the owning package, but it's still better that hard-coding the name.
(Especially as I put all my packages in the same directory anyway ;-)


> This does leave me wondering how difficult it would be to make it all
> simpler for new users, though.  It seems like integrating your locator
> classes with some means of binding packages' icons into the deployed image
> could remove some annoying barriers.

I've been pondering the same question, or a very similar one: "how can I make
it simpler for /me/" ;-)   What I lack is a good way of identifying the
external resources that each package uses.

I have a half-way solution which I use when I'm rebuilding the ZIP files to go
on my website (and automatic process).  Each package (that I put on the
website) has a list of necessary external files (icons, bitmaps, DLLs, etc)
that have to be included in the ZIP.  That list is stored in the Package
object's
    propertyAt: ExternalResourceFileNames
which is set in the package's post-install script.  If you have any of my
software then you can probably find examples of that.  It's a bit clunky, and
I'd like to find something requireing less manual configuration, but it does
work.  I suppose that could be extended to all packages, and used by a custom
ImageStripper[*].  (Come to think of it, that could also gather up any
necessary DLLs, etc, as part of the same operation.)

([*] Ideally, factored out of the stripper class itself.  We have to use
ImageStripper subclasses for other reasons, so it should be easy to use this
stuff from /any/ ImageStripper.)


> I'm thinking of a process like: scan the package's dependencies, exclude
> the OA packages, round up all the icon files in the packages'
> directories, write a resource script for the icons, and compile them into
> a new stub with ResHacker.

Unfortunately that would be too coarse a selection for me -- as I said, I keep
everything together...

Another thing I'd want to do is to copy in any Dolphin resources that it used
(the Booleans' icons, for instance).  And that's a bit tricky to identify until
after image-stripping has finished.  Maybe it'd be possible to hack something
up using the new XML manifest, but that would mean each deployment was
dependent on the previous one -- which I'd rather avoid).


> It might be possible to utilize ResHacker's command-line features combined
> with your package-relative stuff to create custom stubs at (or just
> before) deployment time.  (ResHacker can easily do bulk loading of
> resources into DLL and EXE files.  Of course, Dolphin will eventually
> have that capability itself; I'm sure ImageStripper>>updateIconResource:
> is going to be done any day now.  ;^)

FWIW I put together some stuff for manipulating resouces a while back.  It uses
the Windows APIs directly.  Unfortunately, there's a nasty bug in the Windows
stuff and deleting resources corrupts the resource segment.  I did find a
(rather ugly) workaround, but have never gone back to build it into the classes
properly, so I haven't published that stuff yet (although I've always intended
to do so).

I have just remembered that I put it on my "ephemera" website when I was asking
here for help with testing it last year, and have never removed it.  So if
anyone wants to play with it, it's still at:
    http://ephemera.metagnostic.org/code/RWT.zip
That includes both the correct version and the one with the workaround.  Read
/all/ the class comment of WindowsResourceWriter to understand why you should
not use that class directly, but use its sub-class WindowsResourceWriterAlt
instead.


    -- chris