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.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read