/*
 * Richard A. DeVenezia, 6/16/2001
 * http://www.devenezia.com
 */

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

unsigned int hWndCount;
unsigned int enumCount;
unsigned int maxCount;
unsigned long* enumArray;

BOOL CALLBACK EnumChildWindowsCallbackUsedByGetProcessChildWindows ( HWND hWnd, LPARAM lParam )
{
	// lParam contains the hWnd of the child's parent window

	enumCount ++;

	if ( enumCount < maxCount )
	{
		*enumArray = lParam;
		enumArray ++;

		*enumArray = (unsigned long) hWnd;
		enumArray ++;
	}

	return TRUE;
}
// EnumChildWindowsCallbackUsedByGetProcessChildWindows


BOOL CALLBACK EnumWindowsCallbackUsedByGetProcessChildWindows ( HWND hWnd, LPARAM lParam )
{
	// lParam contains the id of the process that wants it's windows
	// system menu changed to disallow the close item

	DWORD pid ;

	// Determine the id of the process that owns the window

	GetWindowThreadProcessId ( hWnd, &pid );

	// Determine if the process is the process of interest

	if (pid == (DWORD) lParam)
	{
		// Invoke the child window enumerator.
		// EnumChildWindows will invoke the callback procedure for each top level window,
		// passing in the HWND and the parent's hWnd

		enumCount ++;

		if ( enumCount < maxCount )
		{
			*enumArray = (unsigned long) hWnd;
			enumArray ++;

			*enumArray = 0;
			enumArray ++;
		}

		EnumChildWindows ( hWnd, EnumChildWindowsCallbackUsedByGetProcessChildWindows, (LPARAM) hWnd );
		hWndCount ++ ;
	}

	return TRUE;  // returning true indicates the enumeration should continue
}
// EnumWindowsCallbackUsedByGetProcessChildWindows



DWORD GetProcessChildWindows ( unsigned long *handleArray, unsigned long nHandles )
{
	// handleArray is assumed to be an array in contiguous memory [ nHandles, 2 ]
	// wherein each element is 4 bytes capable of holding a windows HWND 32-bit value
	// The [,1] element will contain the parent HWND and
	// the [,2] element will contain a child HWND
	//
	// If nHandles indicates more space than is actually present in handleArray -and-
	// the enumeration process exceeds the capacity of handleArray then
	// some sort of unchecked failure will occur when the callback tries to write to
	// an address beyond the space allocated for handleArray.
	//
	// This function returns the actual number of windows encountered during the enumeration process.
	// If this number is larger than nHandles, only nHandles worth of information
	// will be placed in the array and the caller should allocate more space before trying again.
	//
	// Note: This first encounter of a top-level window will indicate a child window zero (0).
	//       This is for the cases in which a top-level window does not have child windows

	DWORD pid;

	enumArray = handleArray;
	maxCount = nHandles;

	hWndCount = 0;
	enumCount = 0;

	// Get the process id of the calling process

	pid = GetCurrentProcessId ();

	// Invoke the top level window enumerator.
	// EnumWindows will invoke the callback procedure for each top level window,
	// passing in the HWND and the pid

	EnumWindows ( EnumWindowsCallbackUsedByGetProcessChildWindows, pid );

	return hWndCount << 8 | enumCount;
}
// GetProcessChildWindows



BOOL CALLBACK EnumWindowsCallbackUsedByDisableProcessWindowsSystemMenuCloseItem( HWND hWnd, LPARAM lParam )
{
	// lParam contains the id of the process that wants it's windows
	// system menu changed to disallow the close item

	DWORD pid ;
	HMENU hMenu ;

	// Determine the id of the process that owns the window

	GetWindowThreadProcessId ( hWnd, &pid );

	// Determine if the process is the process of interest

	if (pid == (DWORD) lParam)
	{
		// Obtain a handle to the windows system menu

		hMenu = GetSystemMenu(hWnd, FALSE) ;
		if (hMenu != NULL) {
			// Grey the close item (will also grey the X icon)
			EnableMenuItem (hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
		}
	}

	return TRUE;  // returning true indicates the enumeration should continue
}
// EnumWindowsCallbackUsedByDisableProcessWindowsSystemMenuCloseItem



void DisableProcessWindowsSystemMenuCloseItem()
{
	DWORD pid;

	// Get the process id of the calling process

	pid = GetCurrentProcessId ();

	// Invoke the top level window enumerator.
	// EnumWindows will invoke the callback procedure for each top level window,
	// passing in the HWND and the pid

	EnumWindows ( EnumWindowsCallbackUsedByDisableProcessWindowsSystemMenuCloseItem, pid );
}
// DisableProcessWindowsSystemMenuCloseItem