How to Save and Load a Windows Region with the Win32 API

This article is a small tip on how to save a Windows region to a file using GetRegionData and how to load and re-create this saved region with ExtCreateRegion using standard Win32 API calls.

SaveRegion

The SaveRegion function (see below for the complete function) first will create a region. For demonstration purposes, it will create an elliptic region as follows:

// Create some elliptic region as demonstration
RECT rc;
GetClientRect(g_hWnd, &rc);
HRGN hRgn = ::CreateEllipticRgn(0, 0, rc.right, rc.bottom);

Before you can retrieve the region data with GetRegionData, you need to figure out how much memory is required to hold the region data. This is done by calling GetRegionData with the third parameter set to NULL. The third parameter is normally a pointer to memory where to store the region data. When this is NULL, the function will return the number of required bytes.

// Get the size in bytes of our created region
int iSize = ::GetRegionData(hRgn, sizeof(RGNDATA), NULL);

Now that you have the required memory size, you can allocate the right amount of memory and call GetRegionData again,again but this time the third parameter will have a pointer to your allocated memory:

// Allocate memory to hold the region data
RGNDATA* pData = (RGNDATA*)calloc(iSize, 1);
pData->rdh.dwSize = iSize;

// Get the region data
int iSize2 = ::GetRegionData(hRgn, iSize, pData);
// Sanity check
if (iSize != iSize2)
   ::MessageBox(g_hWnd, L"Something wrong with GetRegionData...",
                L"Error", MB_ICONERROR);

In the code above, there is also a small check to make sure you got the right amount of information. Now, you have your region data stored in pData and can save this to a file as follows:

// Save region data to a file
FILE* f = fopen("test_region.rgn", "wb");
fwrite((char*)pData, sizeof(char), iSize, f);
fclose(f);
Important Note: When opening the file, make sure to open it in binary mode. If you use fopen like above, you have to specify the "b" parameter to open the file in binary mode.
Note: In production code, you will need to perform error checking on all file-related functions such as fopen and fwrite.

After this, you can free your allocated memory and delete your region as follows:

// Free allocated memory
free(pData);

// Delete our region
::DeleteObject(hRgn);

The full code of the SaveRegion function is shown below:

void SaveRegion()
{
   // Create some elliptic region as demonstration
   RECT rc;
   GetClientRect(g_hWnd, &rc);
   HRGN hRgn = ::CreateEllipticRgn(0, 0, rc.right, rc.bottom);

   // Get the size in bytes of our created region
   int iSize = ::GetRegionData(hRgn, sizeof(RGNDATA), NULL);

   // Allocate memory to hold the region data
   RGNDATA* pData = (RGNDATA*)calloc(iSize, 1);
   pData->rdh.dwSize = iSize;

   // Get the region data
   int iSize2 = ::GetRegionData(hRgn, iSize, pData);
   // Sanity check
   if (iSize != iSize2)
      ::MessageBox(g_hWnd, L"Something wrong with GetRegionData...",
                   L"Error", MB_ICONERROR);

   // Save region data to a file
   FILE* f = fopen("test_region.rgn", "wb");
   fwrite((char*)pData, sizeof(char), iSize, f);
   fclose(f);

   // Free allocated memory
   free(pData);

   // Delete our region
   ::DeleteObject(hRgn);
}

LoadRegion

The workflow to load the saved region is to load all the data back from the file in a memory buffer and then use ExtCreateRegion to create a region from this data.

First, the file is opened and the size of the file is retrieved. This size will be used to allocated enough memory to load the entire file into memory.

// Open file to read region data from
FILE* f = fopen("test_region.rgn", "rb");

// Get size of the file
fseek(f, 0, SEEK_END);
int iSize = ftell(f);
fseek(f, 0, SEEK_SET);
Important Note: When opening the file, make sure to open it in binary mode. If you use fopen like above, you have to specify the "b" parameter to open the file in binary mode.

Now that you know the size of the data, you allocate your memory and read the entire file into your buffer as follows:

// Allocate memory to hold the region data
RGNDATA* pData = (RGNDATA*)calloc(iSize, 1);

// Read region data from file
fread((char*)pData, sizeof(char), iSize, f);
fclose(f);
Note: In production code, you will need to perform error checking on all file-related functions such as fopen and fread.

Now, you use ExtCreateRegion to let Windows create a new region based on your loaded region data:

// Create region from loaded region data
HRGN hRgn = ::ExtCreateRegion(NULL, iSize, pData);

The first parameter is a transformation that should be applied to your region. If you specify NULL, your region will not be transformed in any way.

For demonstration purposes, you now assign your recreated region as a region to your window so that you can visually see that the region was properly loaded.

// As a demonstration, set the loaded region as window region
// so it is visually clear that it got loaded correctly.
::SetWindowRgn(g_hWnd, hRgn, TRUE);

Everything is finished now, so you can free your allocated memory.

// Free allocated memory
free(pData);

The full code of the LoadRegion function is shown below:

void LoadRegion()
{
   // Open file to read region data from
   FILE* f = fopen("test_region.rgn", "rb");

   // Get size of the file
   fseek(f, 0, SEEK_END);
   int iSize = ftell(f);
   fseek(f, 0, SEEK_SET);

   // Allocate memory to hold the region data
   RGNDATA* pData = (RGNDATA*)calloc(iSize, 1);

   // Read region data from file
   fread((char*)pData, sizeof(char), iSize, f);
   fclose(f);

   // Create region from loaded region data
   HRGN hRgn = ::ExtCreateRegion(NULL, iSize, pData);

   // As a demonstration, set the loaded region as window region
   // so it is visually clear that it got loaded correctly.
   ::SetWindowRgn(g_hWnd, hRgn, TRUE);

   // Free allocated memory
   free(pData);
}

Attached to this article is a zip file containing a little sample project with the SaveRegion and LoadRegion functions. This sample project is a simple Win32 API application showing one window with a menu. There is a menu called Region with items Save and Load. First, click the Save menu item to save the elliptic region to a file and then use the Load menu item to load and re-create that saved region.



About the Author

Marc Gregoire

Marc graduated from the Catholic University Leuven, Belgium, with a degree in "Burgerlijk ingenieur in de computer wetenschappen" (equivalent to Master of Science in Engineering in Computer Science) in 2003. In 2004 he got the cum laude degree of Master In Artificial Intelligence at the same university. In 2005 he started working for a big software consultancy company. His main expertise is C/C++ and specifically Microsoft VC++ and the MFC framework. Next to C/C++, he also likes C# and uses PHP for creating webpages. Besides his main interest for Windows development, he also has experience in developing C++ programs running 24x7 on Linux platforms and in developing critical 2G,3G software running on Solaris for big telecom operators.

Downloads

Comments

  • good article...

    Posted by zhouzhengle on 06/13/2011 07:50am

    good article...thanks ..

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Hurricane Sandy was one of the most destructive natural disasters that the United States has ever experienced. Read this success story to learn how Datto protected its partners and their customers with proactive business continuity planning, heroic employee efforts, and the right mix of technology and support. With storm surges over 12 feet, winds that exceeded 90 mph, and a diameter spanning more than 900 miles, Sandy resulted in power outages to approximately 7.5 million people, and caused an estimated $50 …

  • The rapid evolution of enterprise storage technologies, combined with external forces, like the explosion of big data, can cause Linux® and server administrators to play catch-up when it comes to storage. Running a bunch of monolithic storage devices and proprietary, disconnected technologies forces administrators to spend valuable time creating and managing complex solutions. To reduce complexity and enable rapid deployment of new technologies and applications, server administrators need a single open …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds