Solved

GlobalAlloc

Posted on 1997-09-22
8
881 Views
Last Modified: 2006-11-17
I am using C++ in Windows 3.1

The Win API provides the following example for GlobalAlloc:

HGLOBAL hglb;
void FAR* lpvBuffer;

hglb = GlobalAlloc(GPTR,1024);
lpvBuffer = GlobalLock(hglb);
.
.
.
GlobalUnlock(hglb);
GlobalFree(hglb);

What I would like is an example of the above in a coded example so that I can get a better idea how I can utilise GlobalAlloc in my programs.

your help is appreciated

Richard
0
Comment
Question by:aa941438
  • 4
  • 2
  • 2
8 Comments
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1170227
GlobalAlloc is pretty much like a malloc except for two things.  Firstly is where it gets its memory from, and second is how you access it.  Memory allocated with GlobalAlloc can potentially be moved about in memory without you knowing - and can even be swapped out to disk.  Because of this, if GlobalAlloc returned a pointer, it would be of little use to you as you cannot guarantee that it will point to your allocated data.  So instead you get a "handle".  Windows keeps a mapping between the handle and where the actual memory is in memory.  However, to get at the allocated data your program needs a pointer.  So, what you need to do is to call GlobalLock which locks that allocated memory so that windows wil not move it and returns to you a pointer to its current location.  When you are finished with the data, you unlock the handle, which then allows windows to manage the block of data again.

Hope this helps - let me know if you want more help.

0
 

Author Comment

by:aa941438
ID: 1170228
While I greatly appreciate the effort taken to provide a description of GlobalAlloc this was not really what I was after as I have much of this information at hand.

A coded example of GlobalAlloc was what I asked for as this is what would really help me. There is no substitute for an example.

 
0
 
LVL 2

Accepted Solution

by:
alexxx earned 2000 total points
ID: 1170229
Here is an example (simple list implementation):

typedef struct tagLIST
{
   DWORD dwPayLoad; //data contained in a list element
   LPLIST lpNext;  //points to the next list element
} LIST, FAR* LPLIST;

main()
{
   LPLIST lpMyList;

   lpMyList = ListCreate();

   ListAdd(lpMyList, 1L);
   ListAdd(lpMyList, 2L);
   ListAdd(lpMyList, 3L);

   ListDestroy(lpMyList);  //deallocates all the memory used
}  //main()

LPLIST ListCreate(void)
{
   HGLOBAL hMem;
   LPLIST lpTmp;
   
   hMem = GlobalAlloc(GPTR, sizeof(LIST));
   lpTmp = GlobalLock(hMem);
   if(NULL != lpTmp)
      lpTmp->lpNext = NULL;
 
   return lpTmp;
}  //ListCreate()

BOOL ListAdd(LPLIST lpList, DWORD dwPayLoad)
{
   HGLOBAL hMem;
   LPLIST lpTmp;
   
   hMem = GlobalAlloc(GPTR, sizeof(LIST));
   lpTmp = GlobalLock(hMem);
   if(NULL != lpTmp)
   {
      lpTmp->lpNext = NULL;
      lpTmp->dwPayLoad = dwPayLoad;

      while(lpList->lpNext)
         lpList = lpList->lpNext;

      lpList->lpNext = lpTmp;
      return TRUE;
   }
   else
      return FALSE;
}   //ListAdd()

void ListDestroy(LPLIST lpList)
{
   LPLIST lpTmp;

   while(lpList)
   {
      lpTmp = lpList->lpNext;
      GlobalUnlock(HIWORD((DWORD)lpList));
      GlobalFree(HIWORD((DWORD)lpList));
      lpList = lpTmp;
   }
}   //ListDestroy()

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1170230
While the above is a use of GlobalAlloc, it is not a GOOD use of it.

You should not keep a handle locked for longer than you really need.

Now, of course, in this example, the whole program runs very quickly, but in a REAL example, you would not call GlobalLock immediately after GlobalAlloc and then GlobalUnlock immediately beforeGlobalFree.

You creation routine would allocate the handle and keep (in this case) only lpList.  Then whenever you wanted to add to the list, you would GlobalLock, get the pointer, do things to the list and then unlock it.

You destroy procedure would then just do a global free.

Here is improved code which also uses a class to encapulate access to the list.

// this is the data we will be putting in our global storage
typedef struct tagLIST {
      DWORD dwPayLoad;      // data contained in a list element
      HANDLE hNext;            // next list element
} LIST, FAR* LPLIST;

// this class encapulates access to the list
class List {
      HANDLE hFirst;            // first list element
      HANDLE hLast;            // last list element
public:
      List();
      ~List();
      BOOL Add(DWORD dwPayLoad);
}

main() {
      List myList;
      myList.Add(1L);
      myList.Add(2L);
      myList.Add(3L);
}

// construct the list - set handles to NULL
List::List()
: hFirst(NULL)
, hLast(NULL)
{}

// destruct the list by free all items
List::~List() {
      HANDLE hNext;
      // follow the chain for each item
      for (HANDLE hThis = hFirst; hThis; hThis = hNext) {
            // lock handle to get next pointer
            LPLIST p = GlobalLock(hThis);
            if (p) hNext = p->hNext;
            GlobalUnlock(hThis);
            // now free it
            GlobalFree(hThis);
      }
}

// add an item to the end of list
BOOL List::Add(DWORD dwPayLoad) {
      // allocate a new item
      hTmp = GlobalAlloc(GPTR, sizeof(LIST));
      if (! hTmp) return FALSE;
      // get a pointer to it
      pTmp = GlobalLock(hTmp);
      if (! lpTmp) return FALSE;
      // store the data
      pTmp.dwPayLoad = dwPayLoad;
      pTmp.hNext = NULL;
      GlobalUnlock(hTmp);
      // update old last item to point to new item
      if (hLast) {
            LPLIST pLast = GlobalLock(hLast);
            if (pLast) pLast->hNext = hTmp;
            GlobalUnlock(hLast);
      }
      // update pointer to end of list
      hLast = hTmp;
      // update pointer to start of list
      if (! hFirst) hFirst = hLast;
}


Please reject previous and accept this answer if you prefer it.

Roger

0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1170231
PS: just found tried compiling the above - found a couple of little bugs.

Here is fixed code (which compiled with no warnings).  Also, note the use of static_cast to cast return from GlobalLock

#include <windows.h>

// this is the data we will be putting in our global storage
typedef struct tagLIST {
      DWORD dwPayLoad;      // data contained in a list element
      HANDLE hNext;            // next list element
} LIST, FAR* LPLIST;

// this class encapulates access to the list
class List {
      HANDLE hFirst;            // first list element
      HANDLE hLast;            // last list element
public:
      List();
      ~List();
      BOOL Add(DWORD dwPayLoad);
};

void main() {
      List myList;
      myList.Add(1L);
      myList.Add(2L);
      myList.Add(3L);
}

// construct the list - set handles to NULL
List::List()
: hFirst(NULL)
, hLast(NULL)
{}

// destruct the list by free all items
List::~List() {
      HANDLE hNext;
      // follow the chain for each item
      for (HANDLE hThis = hFirst; hThis; hThis = hNext) {
            // lock handle to get next pointer
            LPLIST p = static_cast<LPLIST>(GlobalLock(hThis));
            if (p) hNext = p->hNext;
            GlobalUnlock(hThis);
            // now free it
            GlobalFree(hThis);
      }
}

// add an item to the end of list
BOOL List::Add(DWORD dwPayLoad) {
      // allocate a new item
      HANDLE hTmp = GlobalAlloc(GPTR, sizeof(LIST));
      if (! hTmp) return FALSE;
      // get a pointer to it
      LPLIST pTmp = static_cast<LPLIST>(GlobalLock(hTmp));
      if (! pTmp) return FALSE;
      // store the data
      pTmp->dwPayLoad = dwPayLoad;
      pTmp->hNext = NULL;
      GlobalUnlock(hTmp);
      // update old last item to point to new item
      if (hLast) {
            LPLIST pLast = static_cast<LPLIST>(GlobalLock(hLast));
            if (pLast) pLast->hNext = hTmp;
            GlobalUnlock(hLast);
      }
      // update pointer to end of list
      hLast = hTmp;
      // update pointer to start of list
      if (! hFirst) hFirst = hLast;
      return TRUE;
}

Please reject previous and accept this answer if you prefer it.

Roger

0
 

Author Comment

by:aa941438
ID: 1170232
Many thanks, a great help much appreciated
0
 
LVL 2

Expert Comment

by:alexxx
ID: 1170233
OK, I know this list implementation is ain't good at all, it's very bad actually, it wastes Windows global heap resources. But it IS a good example because it's simple.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1170234
alexx - my problem with your example was NOT that it was simple, but that it did not show the correct way to use handles and to get access thru lock and unlock.

Your example allocated the space ok but it locked it and KEPT IT LOCKED until the end of the program.  This is NOT the way to use global alloced memory.

Also you stored the pointer returned by the lock and used that rather than the handle.  This is also bad because ,when you do start locking and unlocking, the pointer will not be valid.  Rather, you should keep the handle only and lock to get the pointer when you really need to get at the daat and then unlock when you are finished (and the pointer is then no longer valid).


But I DID appreciate the simplicity of your example and simply fixed it up a bit to make better use of handles and also (for the heck of it) put it in a class (as this is a C++ topic area).

Roger

0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now