win32 Memory Management

The GlobalAlloc() and LocalAlloc() functions should not be used, but they are available in the win32 API. Back in the 16 bit days, a long long time ago in a galaxy far, far away, these functions determined what sort of memory segments were used. Nowadays, the local heap and the global heap are not distinguished, rendering GlobalAlloc() and LocalAlloc() the same. In fact, GlobalAlloc() and LocalAlloc() are just wrappers for the HeapAlloc() function.

The GlobalAlloc() function allocates a block of memory from the heap. Memory allocated with GlobalAlloc() is always read-write. The GlobalAlloc() function takes two arguments. The first argument is a one of five possible flags.The GHND flag is a combination of the GMEM_MOVEABLE and the GMEM_ZEROINIT flags. The GMEM_MOVEABLE flag allocates moveable memory. This flag cannot be combined with the GMEM_FIXED flag, which allocates fixed memory. The GMEM_FIXED flag returns a pointer value to the memory block. To access this memory, cast the return value as a pointer. The GMEM_ZEROINIT flag initializes the memory contents to 0. The GPTR flag is a combination of the GMEM_FIXED and the GMEM_ZEROINIT flags.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    printf("GHND = %d\n", GHND);
    //equal to GHND
    printf("GMEM_MOVEABLE | GMEM_ZEROINIT = %d\n", GMEM_MOVEABLE | GMEM_ZEROINIT);
    printf("GMEM_MOVEABLE = %d\n", GMEM_MOVEABLE);
    printf("GMEM_FIXED = %d\n", GMEM_FIXED);
    printf("GMEM_ZEROINIT = %d\n", GMEM_ZEROINIT);
    printf("GPTR = %d\n", GPTR);

    return 0;
}

The GlobalAlloc() function returns the handle to the allocated memory object, HGLOBAL, if successful; otherwise, it returns NULL.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    //moveable memory
    HGLOBAL hG = GlobalAlloc(GHND, 256);

    //returns NULL if it did not work
    if(hG==NULL){
        printf("Memory was not allocated.\n");
    } else {
        printf("Memory was allocated.\n");
    }

    return 0;
}

In order to cast the HGLOBAL handle to a pointer we can use, we must first lock the memory using the GlobalLock() function. The GlobalLock() function locks a global memory object and returns a pointer to the first byte of the object’s memory block. The locked memory block then cannot be moved or thrown away.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    //moveable memory
    SYSTEM_INFO *structPtrSI;

    //equivalent of GHND
    HGLOBAL hG = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(SYSTEM_INFO));

    if(hG!=NULL){
        printf("Memory allocated!\n");
    }

    structPtrSI = (SYSTEM_INFO*)GlobalLock(hG);

    //NULL if there is a problem
    if(structPtrSI!=NULL){
        printf("Memory is locked.\n");
    }

    return 0;
}

Remember, the GlobalLock() function must be used to obtain a pointer to a memory object allocated with the GlobalAlloc() function with the GMEM_MOVEABLE flag.

To avoid having to lock the memory with GlobalLock(), we could instead pass in the GMEM_FIXED flag instead of GMEM_MOVEABLE.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    
    TAPE_GET_DRIVE_PARAMETERS *structTDParams = 
        (TAPE_GET_DRIVE_PARAMETERS*)GlobalAlloc(GMEM_FIXED, sizeof(TAPE_GET_DRIVE_PARAMETERS));

    if(structTDParams!=NULL){
        printf("Structure allocated.\n");
    }

    return 0;
}

The GlobalFree() function frees a global memory object and invalidates its handle. Freeing a memory block returns the memory to the operating system so it can be reused. All memory blocks allocated within an application ought to be freed before the application exits.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    int *iPtr = NULL;
    HGLOBAL hMovMem = GlobalAlloc(GHND, 256);
    HGLOBAL hFixedMem = GlobalAlloc(GPTR, sizeof(INT));

    if(hMovMem && hFixedMem != NULL){
        printf("Memory allocated.\n");
    }

    iPtr = (int *)hFixedMem;

    *iPtr = 73;

    printf("%d\n", *iPtr);

    iPtr = NULL;

    if((GlobalFree(hFixedMem))==NULL){
        printf("Fixed heap memory freed.\n");
    }

    if((GlobalFree(hMovMem))==NULL){
        printf("Moveable heap memory freed.\n");
    }
    return 0;
}

Remember, there should be a matching call to GlobalFree() for every call to GlobalAlloc().

Interested in learning standard C? Check out http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/.

Advertisements

Fun with Function Pointers

A function pointer is a pointer that holds the address of a function. Being able to create pointers to point to functions is awesome but also terrifying, in a way. The great thing about function pointers is that they provide us with a means for executing functions in an order that may not be known at compile time and without needing conditional statements. Function pointers provide support for alternate execution paths.

To declare a function pointer, we surround the function name with parentheses and add an asterisk to the front of the name. A rough outline of a function pointer follows the form return_type (*function_name)(parameters).The asterisk indicates that it is a pointer, and the parentheses make it a function pointer.

//returns void no parameters
void (*funcPtrOne)();

//returns int, passed an int
int (*funcPtrTwo)(int)

//returns double, passed two ints
double (*funcPtrThree)(int, int);

//returns char, passed string
char (*funcPtrFour)(const char *szText);

Be aware of the difference between functions that return a pointer versus function pointers. The parentheses around the function name prefixed by an asterisk indicates that it is a function pointer.

To use a function pointer, assign a function’s address to the function pointer. The function pointer and the actual function it is pointing to must have the same signature, i.e. the same return type and parameter types.

 #include <stdio.h>

//func pointer
int (*fPtrIntCharChar)(char, char);

//function to compare two char parameters
//if first param is greater than second param
//or it is the only capital letter
//returns positive int
//if second param is greater than first param
//or it is the only capital letter
//returns negative int
int compareLetters(char cX, char cY);

int _tmain(int argc, _TCHAR* argv[])
{
    int iRVal;

    char cLetters[] = {'b', 'f', 'A', 'Q', 'u', 'Z', 'z', 'T', 'b', 'C', 'e', 'e', 'r', 'V', 'v'};

    const int Array_Bounds = sizeof(cLetters) / sizeof(char);

    fPtrIntCharChar = compareLetters;

    for(int i = 1; i < Array_Bounds; i++){
        iRVal = fPtrIntCharChar(cLetters[i-1], cLetters[i]);
        if(iRVal==0){
            printf("%c and %c are equal.\n", cLetters[i-1], cLetters[i]);
        }
        if(iRVal>0){
            printf("%c comes before %c.\n", cLetters[i-1], cLetters[i]);
        }
        if(iRVal<0){
            printf("%c comes before %c.\n", cLetters[i], cLetters[i-1]);
        }
    }


    return 0;
}

//returns -1 if first character is after
//second character
//returns +1 if first character is before 
//the second character
int compareLetters(char cX, char cY){
    int iDiff = cX - cY;

    //x is greater than y
    //therefore x is after y in the alphabet
    if(iDiff > 0){
        return -1;
    }

    //y is greater than x numerically
    //therefore y is after x in the alphabet
    if(iDiff < 0){
        return 1;
    }

    //two letters are equal
    return iDiff;
}

As we can see above, just like with array names, when we use the name of a function by itself, it returns the function’s address. It is not necessary to use the address of operator. We can even use the comparison operator to verify this.

#include <stdio.h>

void (*funcPtrA)(int a);
double (*funcPtrB)(double a);

void functionOne(int a);
double functionTwo(double a);

int _tmain(int argc, _TCHAR* argv[])
{
    printf("Address for functionOne %p.\n", functionOne);
    printf("Address for functionTwo %p. \n", functionTwo);

    //& operator unnecessary 
    funcPtrA = &functionOne;
    funcPtrB = functionTwo;

    if(funcPtrA == functionOne){
        printf("Same address.\n");
    }

    if(funcPtrB == &functionTwo){
        printf("Still same address.\n");
    }
    return 0;
}

void functionOne(int a){
    printf("Hello %d.\n", a);
}

double functionTwo(double a){
    return a * 19.99;
}

It’s simple enough to declare a type definition for function pointers.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef void (*fPtrVoidVoid)(void);
typedef char*(*fPtrCharCharPtr)(char *);

void functionPrintHello(void);
char * functionChangeString(char *);

int main(void){

    fPtrVoidVoid fpOne = functionPrintHello;
    fPtrCharCharPtr fpTwo = functionChangeString;

    char * szString = fpTwo("Do you have stairs in your house?");

    fpOne();
    printf("%s\n", szString);

    //clean up
    free(szString);

    return 0;
}

void functionPrintHello(void){
    printf("Saluton Mundo! ");
}

char * functionChangeString(char * szParam){
    char *rszVal = (char *)malloc((strlen(szParam) + 256)*sizeof(char));
    strcpy(rszVal, szParam);
    strcat(rszVal, " I am protected.");
    return rszVal;
}

It is not difficult to pass a function pointer, we must simply use the function pointer declaration as a parameter of a function.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int (*fptrInt)(int, int);

void doSomething(int iArray[], int bounds, fptrInt);
int sum(int x, int y);
int multiply(int x, int y);

int main(void){

    int iArray[] = {80, 443, 25, 161, 143, 389, 156, 21};
    const int iBounds = sizeof(iArray) / sizeof(int);

    doSomething(iArray, iBounds, sum);
    
    printf("And now for something completely different.\n");

    doSomething(iArray, iBounds, multiply);

    return 0;
}

void doSomething(int iArray[], int bounds, fptrInt func){
    for(int i = 0; i < bounds - 1; i+=2){
        printf("%d.\n", func(iArray[i], iArray[i+1]));
    }
}

int sum(int x, int y){
    printf("Adding %d and %d.\n", x, y);
    return x + y;
}

We can see that function pointers can add a high degree of flexibility to code. There are performance considerations to be aware of – on the lower level, function pointers can disrupt the processor pipeline, which can negatively impact performance.

File Locking with win32

Windows provides four functions for locking and unlocking files. The LockFIle() and LockFileEx() functions engage locks, and the Unlock() and UnlockFileEx() functions remove locks.

The LockFile() function takes five arguments and returns a Boolean value. The first argument is a handle to the file. The second argument is a  DWORD value indicating the low-order bits of the starting offset in the file where the lock should begin. The third argument is a DWORD value indicating the high-order bits of the starting offset in the file where the lock should begin; we will set this value to 0. The fourth argument is the low-order bits of the byte length in the file to be locked. The fifth argument is the high-order bits of the byte length in the file to be locked, we will set this to 0, as well.

#include <Windows.h>
#include <stdio.h>

int main(void){

	HANDLE hFileHandle;
	BOOL bSuccess;
	char *szFilename = "testing.txt";
	char szBuffer[256];

	//create new file
	//with both reading and writing authority
	//and reading and writing sharing
	hFileHandle = CreateFile(szFilename, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);

	if(hFileHandle == INVALID_HANDLE_VALUE){
		printf("Error creating handle to new file.\n");
		exit(EXIT_FAILURE);
	}

	//lock the file for the buffer length
	bSuccess = LockFile(hFileHandle, 0, 0, sizeof(szBuffer), 0);
	if(bSuccess){
		printf("File lock on %s secured.\n", szFilename);
	}

	//now let's release the lock
	bSuccess = UnlockFile(hFileHandle, 0, 0, sizeof(szBuffer), 0);

	if(bSuccess){
		printf("File lock on %s released.\n", szFilename);
	}

	//close the handle
	CloseHandle(hFileHandle);
	return 0;

}

We can see here how easy it is to lock and later unlock a range of bytes. Locks cannot overlap a previously locked region, and locks are not inherited by child processes. Our next program will demonstrate this by using a bit of magic via the GetModuleFileName() function, which will fetch us the name of the executable that created the current process.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>


int _tmain(int argc, _TCHAR* argv[])
{
	BOOL bSuccess;

	//in parent process
	if(!(argv[1])){
		TCHAR szFileName[512];

		//create file
		HANDLE hCreate = CreateFile(_T("test.txt"), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
		CloseHandle(hCreate);

		//get executable for this program
		GetModuleFileName(NULL, szFileName, _tcslen(szFileName));
		_tprintf(_T("Filename for this executable is %s.\n"), szFileName);
		
		_tcscat_s(szFileName, _T(" childprocess"));

		//create child process
		STARTUPINFO structSI;
		PROCESS_INFORMATION structPI;

		GetStartupInfo(&structSI);

		CreateProcess(
			NULL,
			szFileName, //command line
			0, //process attributes
			0, //thread attributes
			FALSE, //handle inheritance is false
			0, //no creation flags
			NULL, //use parent's environment
			NULL, //use parent's directory
			&structSI,
			&structPI
			);

		HANDLE hFileHandle = CreateFile(_T("test.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);

		bSuccess = LockFile(hFileHandle, 0, 0, 1000, 0);

		if(!bSuccess){
			printf("Lock error %d in process %d.\n", GetLastError(), GetCurrentProcessId());
		} else {
			printf("File locked in process %d.\n", GetCurrentProcessId());
		}

		//wait for child process to close
		WaitForSingleObject(structPI.hProcess, INFINITE);
		//close this process's handle to the child process
		CloseHandle(structPI.hProcess);

		//unlock file
		if(UnlockFile(hFileHandle, 0, 0, 1000, 0)){
			printf("File unlocked in parent process.\n");
		}

		CloseHandle(hFileHandle);

	} else {
		printf("In child process (%d).\n", GetCurrentProcessId());

		//sleep to make sure parent process gets lock first
		Sleep(1000);

		HANDLE hFileHandle = CreateFile(_T("test.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);

		//this shouldn't work
		bSuccess = LockFile(hFileHandle, 0, 0, 1000, 0);
		
		if(!bSuccess){
			printf("Lock error %d in process %d.\n", GetLastError(), GetCurrentProcessId());
		} 

		CloseHandle(hFileHandle);

	}

	return 0;
}

The LockFileEx() and UnlockFileEx() functions enable us to block on lock requests. If the file handle is opened for asynchronous I/O, then by default LockFileEx() will operate asynchronously, unless the LOCKFILE_EXCLUSIVE_LOCK flag is specified. If the file handle is not opened for asynchronous I/O, then LockFileEx() blocks until the lock is granted or an error is given.

The LockFileEx() function has six parameters. The first parameter is the file handle for setting the lock on. The second parameter lets us set one or both flags, LOCKFILE_FAIL_IMMEDAITELY and LOCKFILE_EXLUSIVE_LOCK. The LOCKFILE_FAIL_IMMEDIATELY flag controls what happens when the LockFileEx() function tries to lock a range of bytes that already has been locked by another process. If this flag is specified, then LockFileEx() returns immediately with a lock violation, otherwise LockFileEx() will wait for the requested block to become available.

#include <Windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
	
	printf("LOCKFILE_FAIL_IMMEDIATELY = %d\n", LOCKFILE_FAIL_IMMEDIATELY);
	printf("LOCKFILE_EXCLUSIVE_LOCK = %d\n", LOCKFILE_EXCLUSIVE_LOCK);
	printf("Both = %d\n", LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK);

	return 0;
}

While the LockFile() function by defaults obtains an exclusive lock, the LockFileEx() function get a shared lock unless the flag LOCKFILE_EXCLUSIVE_LOCK is specified.

The sixth and final parameter for LockFileEx() is a pointer to an OVERLAPPED structure, that contains two fields we can set, one that indicates what offset we should begin the lock from, and the other being a handle to an event to trigger when the operation has been completed. We will use ZeroMemory() to initialize the OVERLAPPED structure.

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
	BOOL bSuccess;
	HANDLE hFileHandle;
	TCHAR *filename = _T("thefile.txt");
	OVERLAPPED structOverlap;

	hFileHandle = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);

	if(hFileHandle == INVALID_HANDLE_VALUE){
		printf("Error creating file.\n");
		exit(EXIT_FAILURE);
	} else {
		_tprintf(_T("File %s created.\n"), filename);
	}

	//initialize structure
	ZeroMemory(&structOverlap, sizeof(structOverlap));

	bSuccess = LockFileEx(hFileHandle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0, &structOverlap);

	if(bSuccess){
		_tprintf(_T("Lock on file %s.\n"), filename);
	}

	//unlock file
	bSuccess = UnlockFileEx(hFileHandle, 0, 100, 0, &structOverlap);

	if(bSuccess){
		printf("File unlocked.\n");
	}

	return 0;
}

Functions and Program Design

A function is simply a named block of code. A function is like a small program that performs a small, well-defined task. Like the larger program it is a part of, a function is usually fed data to process and can have its own variables.

There are two main types of functions, value-returning functions and void functions. A void function does not return any value.

A function call is a statement or expression that transfers control to a function so that the function can perform its designated task. A function call is executed by calling the name of the function immediately followed by parentheses. If we wish to supply values to the function, we place those values in order within the parentheses, separated by commas. These values constitute arguments to the function, that are passed over to the function’s parameters.

Value parameters are an integral part of functions. Value parameters are in essence a type of variable that a function uses to receive the data it will process. A value parameter has a life separate from the corresponding value sent into the function from the function’s caller; this is true even if that value is itself a variable. In other words, if we change the parameter in the function, the associated value in the rest of the program remains the same; in other words, parameters are a copy of the data, not the original data, and the scope of the parameter is limited to the length of the function.

Let’s start by practicing with some of the predefined mathematical functions from the library math.h. As our program will be using a function from a library file, we must have an include statement specifying that library file. We will be calling the log10() function, which takes a double as an argument and returns a double value. The log10() function finds the natural logarithm, AKA the base 10 algorithm, for a specified value. We recalled here that the logarithm of a number is simply the exponent to which another number, the base, must be raised to produce the number. Thus, log10(100) would return the value 2.

#include <stdio.h>
#include <math.h>

int main(void){

	double x = 100000;
	int y = 1000;

	printf("The base10 log of %f is %f\n", x, log10(x));
	//cast y into double to match parameter
	printf("The base10 log of %d is %f\n", y, log10((double)y));

	return 0;

}

We should remember here that any value a function call supplies to the function is called an argument of the function, whereas the result calculated and returned by the function is known as the return value.

A function expects the argument type to match the parameter type; we can see an example of this in the three functions abs(), labs(), and fabs(). Each of these three functions performs the same task, they return the absolute value of the argument provided. Where they differ is that each function accepts an argument of a different type, abs() accepts an argument of type int, labs() accepts an argument of type long, and fabs() accepts an argument of type double.

#include <stdio.h>
#include <math.h>

int main(void){

    int iX = 1999;
    double dY = -1.05;
    long lZ = 8675309;

    printf("The absolute value of %d is %d\n", iX, abs(iX));
    printf("The absolute value of %f is %f\n", dY, fabs(dY));
    printf("The absolute value of %ld is %ld\n", lZ, labs(lZ));

    return 0;

}

When writing a function, we normally split the function into two separate pieces, the declaration and the definition. A function declaration is placed before the main() function. The function declaration specifies what the function is supposed to do and what a programmer should known to call the function. The function definition includes the code that actually performs the task. The function definition includes before this code the function header, which matches the function declaration, except that the function declaration is followed by a semicolon.

#include <stdio.h>

//function declarations go here
void Greet();
void GreetByName(char nameParameter[]);

int main(void){

	char szName[256];

	//call function Greet()
	Greet();

	printf("What is your name? Please enter it here: ");
	scanf(" %s", szName);

	//call function GreetByName()
        //note the single argument
	GreetByName(szName);

	return 0;

}


//function definitions go here
void Greet(){
	printf("\nSaluton Mundo!\n");
}

void GreetByName(char nameParameter[]){
	printf("\nHello, %s\n", nameParameter);
}


As stated earlier, arguments and parameters must match each others data types. Arguments and parameters are matched in order from left to right, so that the first parameter is assigned the value specified in the first argument, etc. When writing a call to a function, we must therefore be careful to give the arguments in the same order as the parameters to which they will be paired.

#include <stdio.h>

//function declaration
//AddUpChange adds up the number of quarters, dimes, nickels and pennies and 
//returns the dollar amount as a double value
double AddUpChange(int quarters, int dimes, int nickels, int pennies);

int main(void){

	int iQuarters, iDimes, iNickels, iPennies;

	iQuarters = 3;
	iDimes = 9;
	iNickels = 4;
	iPennies = 3;

	printf("We have %d quarters, %d dimes, %d nickels, %d pennies.\n", iQuarters, iDimes, iNickels, iPennies);

	printf("That equals $%.2f\n", AddUpChange(iQuarters, iDimes, iNickels, iPennies));

	return 0;

}


double AddUpChange(int quarters, int dimes, int nickels, int pennies){
	double d = 0.0;
	d += quarters * .25;
	d += dimes * .10;
	d += nickels * .05;
	d += pennies * .01;

	return d;

}

In the program above, the double value d is a local variable; local variables are accessible only by statements within the function. Just as with parameters, the memory for local variables is allocated when the computer begins executing the function and is deleted when the function completes its execution.