[comp.windows.ms.programmer] GlobalUnlock

mguyott@eriador.prime.com (03/15/91)

I'm wondering if anyone else has had a problem with the Windows
GlobalUnlock() function?  I began experiencing an unexpected problem so
I wrote the following test code and went into CVW to see what was
happening:

    HANDLE  hMem;
    LPSTR   pMem;

    if ((hMem = GlobalAlloc((GMEM_FIXED | GMEM_ZEROINIT), 64L)) == NULL)
    {
        MessageBox(NULL,
                   "GlobalAlloc( ) failed!",            // Message.
                   "Error in GlobalAlloc( )!",          // Caption.
                   MB_ICONHAND | MB_SYSTEMMODAL | MB_OK);
        return(NULL);
    }

    if ((pMem = (void FAR *)GlobalLock(hMem)) == NULL)
    {
        MessageBox(NULL,
                   "GlobalLock( ) failed!",             // Message.
                   "Error in GlobalLock( )!",           // Caption.
                   MB_ICONHAND | MB_SYSTEMMODAL | MB_OK);
        return(NULL);
    }

    if (GlobalUnlock(hMem)) != NULL)
    {
        MessageBox(NULL,
                   "GlobalUnlock( ) failed!",               // Message.
                   "Error in GlobalUnlock( )!",             // Caption.
                   MB_ICONHAND | MB_SYSTEMMODAL | MB_OK);
        return;
    }

    if (GlobalFree(hMem) != NULL)
    {
        MessageBox(NULL,
                   "GlobalFree( ) failed!",                 // Message.
                   "Error in GlobalFree( )!",               // Caption.
                   MB_ICONHAND | MB_SYSTEMMODAL | MB_OK);
        return;
    }

It turns out that if you call GlobalUnlock() in this case it returns the value
passed in (i.e. hMem).  According to the documentation for GlobalUnlock()
(page 4-247 and 4-248 Ref. Vol. 1):

"The return value specifies the outcome of the function.  It is ZERO (my
emphasis) if the block's lock count was decreased to zero.  Otherwise, the
return value is nonzero."

So I thought that perhaps the block was mysteriously being locked somewhere
else in my progarm so I put the unlock call into a loop so that it was called
until it returned zero.  My program hung in an infinite loop.  When I went
into CVW I traced through the loop 50 times before I gave up.  It seems that
the return value has nothing to do with the lock count in this case.  In fact,
if I ignore the return value, unlock the handle once, and then call
GlobalFree(), GlobalFree() will return SUCCESS (i.e. zero).  And it seems
that everyone is happy.

I then tried changing the GMEM_FIXED flag to GMEM_MOVEABLE.  Everything now
worked fine.  So it seems that calling GlobalUnlock() for memory that was
allocated with the GMEM_FIXED flag will always return failure (actually it
returns the handle that you passed to it).

This is especially annoying if you are trying to be a good Windows
programmer and do things "correctly".  To do things correctly you have
to call GlobalLock() to get a pointer from the memory handle returned by
GlobalAlloc().  On page 16-27 of the Guide to Programming it states that
"You must still call GlobalUnlock in protected mode when you no longer
need the pointer returned by GlobalLock."  Even though calling GlobalLock()
did not increment the lock count for that pointer.

If I wasn't trying to do things "correctly" I could just use the non-standard
shortcuts for global memory allocation/deallocation:

    pMem = (LPSTR)MAKELONG(0, GlobalAlloc((GMEM_FIXED | GMEM_ZEROINIT), 64L));
    GlobalFree((GLOBALHANDLE)HIWORD((LONG)pMem));

then I would have no problems.

So is this a bug that MS knows about?  Is this a bug or is this an ommission
in the documentation?                                        Marc
----
Two of the worst things we teach our children are that a knowledge of science
is nice but not necessary, and a knowledge of sex is necessary but not nice.

Marc Guyott              Constellation Software, Inc.          (508) 620-2800
                         Framingham, Mass. 01701 USA                Ext. 3135
mguyott@primerd.prime.com       ...!{uunet, decwrl}!primerd.prime.com!mguyott