[comp.windows.ms.programmer] How to best represent a list in Windows?

ferdie@coyote.datalog.com (fred jarvis) (04/05/91)

    I want to use a list structure in a Windows application.
Typically, something like
        typedef struct {
           datatype *data;
           listnode *next;
        } listnode;
would be used, with each node dynamically allocated.
    But in Windows, you're supposed to use GlobalAlloc or LocalAlloc,
which return handles, not pointers, then using GlobalLock &
GlobalUnlock or LocalLock etc. to get the pointers for only as long
as you need access.
    If listnode contains handles, rather than pointers, each time a
node is referenced, calls to GlobalLock & ..Unlock (or LocalLock...)
must be made, which seems inefficient to me.
    I know LocalAlloc returns a pointer if called with the
LMEM_FIXED flag, but this is discouraged by the higher powers
(e.g. Petzold).  So what is the best approach to take (besides
going back to DOS) ?

    Fred Jarvis    ferdie@coyote.datalog.com

gpsteffl@sunee.waterloo.edu (Glenn Steffler) (04/06/91)

In article <e2BXZ1w163w@coyote.datalog.com> ferdie@coyote.datalog.com (fred jarvis) writes:
>    I want to use a list structure in a Windows application.
>Typically, something like
>        typedef struct {
>           datatype *data;
>           listnode *next;
>        } listnode;
>would be used, with each node dynamically allocated.

Obviously this is a no-no in Windows, as you must allocate crap loads
of pointers (ie. handles, then locked).  This would eat up the local handle
table to the point where you run out of local heap space.  The same
issue faces you with global memory handles.

>    If listnode contains handles, rather than pointers, each time a
>node is referenced, calls to GlobalLock & ..Unlock (or LocalLock...)
>must be made, which seems inefficient to me.

Can't be done in an independant fashion.  (not portable eh!?)

>    I know LocalAlloc returns a pointer if called with the
>LMEM_FIXED flag, but this is discouraged by the higher powers
>(e.g. Petzold).  So what is the best approach to take (besides
>going back to DOS) ?

As I have said in three or four posts the last four months:

Gold Disks new animation package for M Windows required several
thousand records and has (possibly) hundreds of link lists to keep track of 
the play lists for the animations, and the resource lists of the
bitmaps/sounds/midi etc data.

The only good solution was to write my own custom memory management
stuff which allocates global memory locks it, and then divides said
memory into bite sized (sorry for the pun) chunks for use in
link lists.  Since protect mode allows memory to appear fixed logically
while physically moving around we are totally Windows friendly.
However, we wouldn't run very well in real mode or with expanded (*EMS)
memory as the locked memory segment would impeed normal Windows
memory compaction etc.

Once the block has been fully divided, either re-size it bigger
or if too big (>32k wastes cycles when moving memory in standard mode)
simply allocate another global block and continue the concept.

Thus, my solution is fair, adequate and seems to leave Windows with
plenty of memory management leeway in protect mode.  (Yea, like
what fool would create animations in real mode?? -serious)

Besides allocating blocks with global alloc creates a selector
table entry (descriptor) which must be cached by the processor
every time a new selector is accessed.  Trust me...this can slow
down the processor quite a bit when skipping thru a link list.

>    Fred Jarvis    ferdie@coyote.datalog.com

I realize this solution doesn't make anything easy, as you basically
have to write your own malloc/free routines, but hey, what are you
using your first year data structures course knowledge on anyway? :-)

-- 
Windows Sumo Wrestler                "Bo doesn't know software" - George Brett
  --(Windows 3.0, a combination of modern moodring technology and voodoo)--
"I guess she had a way, of making every night seem bright as day"
`I Don't Believe In Love`   -Queensryche (Oper. Mindcrime)     Glenn Steffler

tonyg@polari.UUCP (Tony Gosling) (04/10/91)

In article <1991Apr5.205519.29757@sunee.waterloo.edu>, gpsteffl@sunee.waterloo.edu (Glenn Steffler) writes:
> In article <e2BXZ1w163w@coyote.datalog.com> ferdie@coyote.datalog.com (fred jarvis) writes:
> >    I want to use a list structure in a Windows application.
> >Typically, something like
> >        typedef struct {
> >           datatype *data;
> >           listnode *next;
> >        } listnode;
> >would be used, with each node dynamically allocated.
> 
> Obviously this is a no-no in Windows, as you must allocate crap loads
> of pointers (ie. handles, then locked).  This would eat up the local handle
> table to the point where you run out of local heap space.  The same
> issue faces you with global memory handles.
[The rest of Glenns answer deleted]

Glenn has given a good description of the issues involved here.

Another way you can do this is to create a local heap in a separate
block of memory allocated by GlobalAlloc.  LocalInit will create
a local heap in that block for you.

Using such a block is not straightforward, you need to set DS to
the segment(selector) of the block before calling any Local
routines.

For example:

hHeap = GlobalAlloc(GMEM_MOVEABLE, 4096L);
segHeap = HIWORD(GlobalLock(hHeap));

LocalInit(segHeap,16,4095);

To alloc from this heap:

_asm	mov	SaveDS, ds;
_asm	mov	ds, segHeap;

hlocal = LocalAlloc(LMEM_FIXED, wBytes);

_asm	mov	ds, SaveDS;

(... far *)(hHeap<<16 + hlocal) will point to this object.

Using Microsoft's C6 based pointers would make referencing
objects in this heap easy.

A couple of notes:
When calling LocalInit, DO NOT use the first 16 bytes of
the object.
The End parameter to LocalIinit will be one less than
the size of the block you allocated.
Apologies for any syntax errors and the lack of typing
in my example.
The SaveDS, wBytes and hlocal variables must be local
ie. stack variables.

Tony Gosling.

jta@locus.com (JT Anderson) (04/10/91)

I have not tried this, but someone who needs to sub-allocate from a block
of memory obtained by GlobalAlloc may want to investigate and report back.

There are functions in MSC 6.0 for allocating from based heaps.  These
functions allow you to manage several heap segments.  They may be just
the ticket for managing a block of memory allocated by GlobalAlloc.

Take a look at _heapadd, _bmalloc, _bfree, etc.  You will probably need
to cheat a little, and the run time library source might be quite helpful,
but not necessary, in determining how these things work.

al@well.sf.ca.us (Alfred Fontes) (04/13/91)

>Another way you can do this is to create a local heap in a separate
>block of memory allocated by GlobalAlloc.  LocalInit will create
>a local heap in that block for you.

The January, 1991 issue of Microsoft Systems Journal has some source
code in it for precisely this technique.  You can download it
from one of the BBS's that keep the source code from the magazine.

pcb@basin06.cacs.usl.edu (Peter C. Bahrs) (04/15/91)

In article <24183@well.sf.ca.us> al@well.sf.ca.us (Alfred Fontes) writes:
>>Another way you can do this is to create a local heap in a separate
>>block of memory allocated by GlobalAlloc.  LocalInit will create
>>a local heap in that block for you.
>
>The January, 1991 issue of Microsoft Systems Journal has some source
>code in it for precisely this technique.  You can download it
>from one of the BBS's that keep the source code from the magazine.

I don't have access to the BBS or even know how to use it.  Can someone
mail a copy of the source if you have it online?  Or post it to cica.
Thanks
pcb@basin04.cacs.usl.edu

gpsteffl@sunee.waterloo.edu (Glenn Steffler) (04/16/91)

Tony G sez, and I quoteth:

>Another way you can do this is to create a local heap in a separate
>block of memory allocated by GlobalAlloc.  LocalInit will create
>a local heap in that block for you.

Good idea for small (and boy do I mean small) linked list.  But I am 
dealing with something over 150k of list memory for a long
(say five minute) movie!  There is no easy way of determining which
list element belongs to which global block unless you allocate the 
memory such that it doesn't matter, and treat the 32 pointers just
like you would in Unix et all.

I also wrote a small memory management function set which doesn't
allocate global blocks and split the memory, but allocates a 
SINGLE GLOBAL block for every list item!  This is a great way to
debug code, because it makes sure that any warry accesses to the 
memory will be trapped in protect mode.  I also made sure the pointer
was aligned in the global block such that no matter how many "extra"
bytes windows afforded me on the global alloc call (found via GlobalSize)
I always return a pointer whose end position (from length given in
my_malloc call) will produce a GP fault if even ONE byte more is read
or written to the block!  Saved my butt couple o' times... :-)

Anyway, just my little ol' ramblings.

-- 
Windows Sumo Wrestler                "Bo doesn't know software" - George Brett
  --(Windows 3.0, a combination of modern moodring technology and voodoo)--
"I guess she had a way, of making every night seem bright as day"
`I Don't Believe In Love`   -Queensryche (Oper. Mindcrime)     Glenn Steffler