SecureVee.c


/*********************************************************************

	$RCSfile: SecureVee.c $
	$Revision: 1.8 $
	$Date: 1998/08/09 05:32:50 $
	$Author: doomer $
	Copyright (c) 1997 John Dumais.  All rights reserved.

**********************************************************************	

Description:

This is the source for a DLL that an application can use to make a
window "own" the desktop.  It installs hot keys to disable
keyboard-initiated window navigation and covers the entire desktop,
so that a user can't get to the rest of the workspace.

*********************************************************************/

#include "SecureVee.h"

/*
	structure to associate window id with atoms that identify hot keys
*/
static struct windowAtomPair hotKeyId;

/* structure to associate window id with original event handler */
static struct windowSubclassPair subclassId;

/* The application window we will work on behalf of */
static HWND mainVeeWindow;

/*
	Our DLL's entry point.  When the DLL is detached, we undow all
	the stuff we did to own the desktop.
*/

BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID reserved) {
	switch (reason) {
		case DLL_PROCESS_DETACH:
			SecureVeeCleanup();
			break;
		default:
			break;
	}
	
	return(TRUE);
}

/*
	Undo all the damage we did.
*/

void __stdcall SecureVeeCleanup(void) {
	cleanUp(&hotKeyId, &subclassId);
	return;
}

/*
	The function where all the fun happens.  We find our application
	window, set up hot keys to prevent keyboard window navigation,
	subclass the applicaton window, remove all the decorations, then
	cover the screen.
*/

int __stdcall SecureVee(void) {
	HWND veeWindow;
	int returnVal=1;
	BOOL hotKeyResult;
	BOOL subclassResult;
	BOOL decorationsResult;
	
	veeWindow=findVeeWindow();
	if (!veeWindow) {
		return(0);
	}
	mainVeeWindow=veeWindow;
	
	hotKeyResult=createHotKey(&hotKeyId, veeWindow);
	if (!hotKeyResult) {
		returnVal=0;
	}

	subclassResult=subclassVeeWindow(&subclassId, veeWindow);
	if (!subclassResult) {
		returnVal=0;
	}

	decorationsResult=removeDecorations(&subclassId, veeWindow);
	if (!decorationsResult) {
		returnVal=0;
	}
	
	return(returnVal);
}

/*
	Take off all the window decorations, so that the application
	window can't be closed, moved or reized interactively.  This is
	accomplished by turning off the window style bits.
*/

BOOL removeDecorations(struct windowSubclassPair *subclassInfo, HWND aWnd) {
	long windowDecorations, newDecorations;

	windowDecorations=GetWindowLong(aWnd, GWL_STYLE);
	if(windowDecorations){
		subclassInfo->flags.stylesValid = 1;
		subclassInfo->styleBits = windowDecorations;
	}
	
	newDecorations = ~(WS_BORDER |
  		WS_CAPTION |
		WS_MAXIMIZEBOX |
		WS_MINIMIZEBOX |
		WS_SYSMENU |
		WS_THICKFRAME |
		WS_OVERLAPPED);

	windowDecorations &= newDecorations;
		
	SetWindowLong(aWnd, GWL_STYLE, windowDecorations);

	/*
		Comment this next block out when debugging.  If you don't you
		won't be able to see the debugger when it hits a break point.
		 Then it's three-finger salute time.
	*/

	return(coverScreen(aWnd, 1 /* top-most */));
} 

/*
	Have the application window cover the visible desktop by getting
	the screen dimensions, moving to the upper left corner, and
	resizing to fill the screen.  If lockPosition is true, set the
	always-on-top property.
*/

BOOL coverScreen(HWND aWnd, BOOL lockPosition) {
	int screenWidth;
	int screenHeight;
	
	screenWidth=GetSystemMetrics(SM_CXSCREEN);
	screenHeight=GetSystemMetrics(SM_CYSCREEN);
	
	if (lockPosition) {
		return(SetWindowPos(aWnd, HWND_TOPMOST, 0, 0, screenWidth, screenHeight, SWP_SHOWWINDOW));	
	}
	
	return(SetWindowPos(aWnd, 0, 0, 0, screenWidth, screenHeight, 0));
}

/*
	Substitute a new event handler in place of the one the
	application defined.  Save off a pointer to the original event
	handler for later restoration.
*/

BOOL subclassVeeWindow(struct windowSubclassPair *subclassInfo, HWND aWnd) {
	subclassInfo->windowPlacement.length = sizeof(subclassInfo->windowPlacement);
	if(GetWindowPlacement(aWnd, &subclassInfo->windowPlacement)){
		subclassInfo->flags.windowPlacementValid = 1;
	}
	subclassInfo->aWnd=aWnd;
	subclassInfo->winProc=SubclassWindow(aWnd, veeSubclass);
	subclassInfo->flags.windowIsSubclassed=1;

	return(1);
}

/*
	Our new event handler.  Eat the hot-key messages, the file-exit
	menu selection, and the ctrl-e keystroke.
*/

LRESULT CALLBACK veeSubclass(
	HWND aWnd,
	UINT aMessage,
	WPARAM wParam,
	LPARAM lParam) {

	switch (aMessage) {
		case WM_HOTKEY:
			return(0);
		case WM_CHAR:
			if(wParam == VEE_CTRL_E){
				return(0);
			}

			break;
		case WM_COMMAND:
			switch(LOWORD(wParam)){
				case VEE_FILE_EXIT:
					return(0);
				default:
					break;
			}
			
			break;
		default:
			break;	
	}

	/* Forward all other messages to the original event handler */
	
	return(CallWindowProc(subclassId.winProc, aWnd, aMessage, wParam, lParam));
}

/*
	Make the world safe from our dementia.  Unregister the hot keys,
	un-subclass the window by re-installing the original event
	handler, put the window decorations back.
*/

void cleanUp(
	struct windowAtomPair *hotKeyInfo,
	struct windowSubclassPair *subclassInfo){
	
	BOOL unregisterResult;
	ATOM deleteAtomResult;
	
	if (hotKeyInfo->flags.altTabInstalled) {
		unregisterResult=UnregisterHotKey(hotKeyInfo->aWindow, (int)hotKeyInfo->altTabAtom);
		hotKeyInfo->flags.altTabInstalled=0;
	}

	if (hotKeyInfo->flags.altF4Installed) {
		unregisterResult=UnregisterHotKey(hotKeyInfo->aWindow, (int)hotKeyInfo->altF4Atom);
		hotKeyInfo->flags.altF4Installed=0;
	}

	if (hotKeyInfo->flags.altReturnInstalled) {
		unregisterResult=UnregisterHotKey(hotKeyInfo->aWindow, (int)hotKeyInfo->altReturnAtom);
		hotKeyInfo->flags.altReturnInstalled=0;
	}

	if (hotKeyInfo->flags.altEscInstalled) {
		unregisterResult=UnregisterHotKey(hotKeyInfo->aWindow, (int)hotKeyInfo->altEscAtom);
		hotKeyInfo->flags.altEscInstalled=0;
	}

	if (hotKeyInfo->flags.altSpaceInstalled) {
		unregisterResult=UnregisterHotKey(hotKeyInfo->aWindow, (int)hotKeyInfo->altSpaceAtom);
		hotKeyInfo->flags.altSpaceInstalled=0;
	}

	if (hotKeyInfo->flags.altTabAtom) {
		deleteAtomResult=GlobalDeleteAtom(hotKeyInfo->altTabAtom);
		hotKeyInfo->flags.altTabAtom=0;
		hotKeyInfo->altTabAtom=(ATOM)0;
	}
	
	if (hotKeyInfo->flags.altF4Atom) {
		deleteAtomResult=GlobalDeleteAtom(hotKeyInfo->altF4Atom);
		hotKeyInfo->flags.altF4Atom=0;
		hotKeyInfo->altF4Atom=(ATOM)0;
	}

	if (hotKeyInfo->flags.altReturnAtom) {
		deleteAtomResult=GlobalDeleteAtom(hotKeyInfo->altReturnAtom);
		hotKeyInfo->flags.altReturnAtom=0;
		hotKeyInfo->altReturnAtom=(ATOM)0;
	}

	if (hotKeyInfo->flags.altEscAtom) {
		deleteAtomResult=GlobalDeleteAtom(hotKeyInfo->altEscAtom);
		hotKeyInfo->flags.altEscAtom=0;
		hotKeyInfo->altEscAtom=(ATOM)0;
	}

	if (hotKeyInfo->flags.altSpaceAtom) {
		deleteAtomResult=GlobalDeleteAtom(hotKeyInfo->altSpaceAtom);
		hotKeyInfo->flags.altSpaceAtom=0;
		hotKeyInfo->altSpaceAtom=(ATOM)0;
	}

	restoreWindow(subclassInfo);
	
	return;
}

/*
	Put the window back the way we found it.
*/

BOOL restoreWindow(struct windowSubclassPair *subclassInfo){
	BOOL result = 1;
	
	if (subclassInfo->flags.windowIsSubclassed) {                        
		SubclassWindow(subclassInfo->aWnd, subclassInfo->winProc);
		subclassInfo->winProc=(WNDPROC)0; 
		subclassInfo->flags.windowIsSubclassed=0;                        
	}                                                              

	if(subclassInfo->flags.stylesValid){
		if(!SetWindowLong(subclassInfo->aWnd, GWL_STYLE,
						  subclassInfo->styleBits)){
			result = 0;
		}

		subclassInfo->flags.stylesValid = 0;
	}

	if(subclassInfo->flags.windowPlacementValid){
		if(!SetWindowPlacement(subclassInfo->aWnd,
							   &subclassInfo->windowPlacement)){
			result = 0;
		}

		/*
			Remove the 'top-most' flag.  Setting the 'nosize' and
			'nomove' flags in the call to SetWindowPos() tells this
			function to ignore the widht, height, x position, and y
			position arguments.
		*/
		
		else{
			if(!SetWindowPos(subclassInfo->aWnd,
							 HWND_NOTOPMOST,
							 0, 0, 0, 0, 
							 SWP_NOREDRAW | SWP_NOSIZE | SWP_NOMOVE)){

				result = 0;
			}
		}

		subclassInfo->flags.windowPlacementValid = 0;
	}

	return result;
}

/*
	Install hot keys to prevent keyboard-initiated window navigation.
*/

BOOL createHotKey(struct windowAtomPair *hotKeyInfo, HWND aWnd) {
	hotKeyInfo->aWindow=aWnd;

	return(installHotKey(hotKeyInfo));
}

/*
	Hot keys are associated with a window and an atom.  Create atoms
	for all of the hot keys we want to register, the install the hot
	keys on behalf of our application window.
*/

BOOL installHotKey(struct windowAtomPair *hotKeyInfo) {
	char altTabAtomString[MAX_STRING_SIZE + 1];
	char altF4AtomString[MAX_STRING_SIZE + 1];
	char altReturnAtomString[MAX_STRING_SIZE + 1];
	char altEscAtomString[MAX_STRING_SIZE + 1];
	char altSpaceAtomString[MAX_STRING_SIZE + 1];
	HMODULE thisModule;
	
	thisModule=GetModuleHandle("SecureVee");

	/*
		Get the strings that identify our hot key atoms from our
		resource table.
	*/
	if(!LoadString(thisModule, IDS_ALT_TAB_ATOM,
			altTabAtomString, MAX_STRING_SIZE)){

		return(0);
	}	

	if(!LoadString(thisModule, IDS_ALT_F4_ATOM,
				   altF4AtomString, MAX_STRING_SIZE)){

		return(0);
	}	

	if(!LoadString(thisModule, IDS_ALT_RETURN_ATOM,
				   altReturnAtomString, MAX_STRING_SIZE)){

		return(0);
	}	

	if(!LoadString(thisModule, IDS_ALT_ESC_ATOM,
				   altEscAtomString, MAX_STRING_SIZE)){

		return(0);
	}
	
	if(!LoadString(thisModule, IDS_ALT_SPACE_ATOM,
				   altSpaceAtomString, MAX_STRING_SIZE)){

		return(0);
	}	

	hotKeyInfo->altTabAtom=GlobalAddAtom(altTabAtomString);
	if (!hotKeyInfo->altTabAtom) {
		return(0);
	}
	hotKeyInfo->flags.altTabAtom=1;

	hotKeyInfo->altF4Atom=GlobalAddAtom(altF4AtomString);
	if (!hotKeyInfo->altF4Atom) {
		return(0);
	}
	hotKeyInfo->flags.altF4Atom=1;

	hotKeyInfo->altReturnAtom=GlobalAddAtom(altReturnAtomString);
	if (!hotKeyInfo->altReturnAtom) {
		return(0);
	}
	hotKeyInfo->flags.altReturnAtom=1;

	hotKeyInfo->altEscAtom=GlobalAddAtom(altEscAtomString);
	if (!hotKeyInfo->altEscAtom) {
		return(0);
	}
	hotKeyInfo->flags.altEscAtom=1;

	hotKeyInfo->altSpaceAtom=GlobalAddAtom(altSpaceAtomString);
	if (!hotKeyInfo->altSpaceAtom) {
		return(0);
	}
	hotKeyInfo->flags.altSpaceAtom=1;

	if(!RegisterHotKey(hotKeyInfo->aWindow, hotKeyInfo->altTabAtom, MOD_ALT,
			VK_TAB)) {

		return(0);
	}
	hotKeyInfo->flags.altTabInstalled=1;

	if(!RegisterHotKey(hotKeyInfo->aWindow, hotKeyInfo->altF4Atom, MOD_ALT,
					   VK_F4)) {

		return(0);
	}
	hotKeyInfo->flags.altF4Installed=1;

	if(!RegisterHotKey(hotKeyInfo->aWindow, hotKeyInfo->altReturnAtom, MOD_ALT,
					   VK_RETURN)) {

		return(0);
	}
	hotKeyInfo->flags.altReturnInstalled=1;

	if(!RegisterHotKey(hotKeyInfo->aWindow, hotKeyInfo->altEscAtom, MOD_ALT,
					   VK_ESCAPE)) {

		return(0);
	}
	hotKeyInfo->flags.altEscInstalled=1;

	if(!RegisterHotKey(hotKeyInfo->aWindow, hotKeyInfo->altSpaceAtom, MOD_ALT,
					   VK_SPACE)) {

		return(0);
	}
	hotKeyInfo->flags.altSpaceInstalled=1;
	
	return(1);
}

/*
	We need to unambiguously identify the window our hosting thread
	created.  We do this by saving off the id of the thread in whose
	context we are presently running, then by enumerating all the top
	level windows, looking for one created by this thread.
*/

HWND findVeeWindow(void) {
	struct windowThreadPair windowThreadInfo;
	BOOL result;
	
	windowThreadInfo.aWindow=(HWND)0;
	windowThreadInfo.windowThread=GetCurrentThreadId();

	result=EnumThreadWindows(windowThreadInfo.windowThread, enumWindowsCallback,
			(LPARAM)&windowThreadInfo);
	
	return(windowThreadInfo.aWindow);
}

/*
	The window enumeration callback function.
*/

BOOL CALLBACK enumWindowsCallback(HWND aWnd, LPARAM windowThreadInfo) {
	DWORD windowThreadId;
	struct windowThreadPair *windowPairInfo;
	
	windowPairInfo=(struct windowThreadPair *)windowThreadInfo;

	/* Which thread created this window? */
	
	windowThreadId=GetWindowThreadProcessId(aWnd, (LPDWORD)0);

	/*
		If it's our thread, we've found the window.  Stop enumerating
		windows
	*/
	if (windowThreadId == (DWORD)windowPairInfo->windowThread) {
		windowPairInfo->aWindow=aWnd;
		return(FALSE);
	}

	/* It's not our thread, keep looking */
	return(TRUE);
}

/*********************************************************************
	$Log: SecureVee.c $
	Revision 1.8  1998/08/09 05:32:50  doomer
	added section in cleanUp() routine to delete the alt tab atom
	and set the structure flags accordingly.
	Revision 1.7  1998/05/06 05:22:12  doomer
	made the two main entry points in the dll use the __stdcall calling convention.
	Revision 1.6  1998/04/19 06:28:28  doomer
	made the restoreWindow() function remove the 'top-most' flag.
	Revision 1.5  1998/04/19 05:32:22  doomer
	added facilities to put target window back the way we found it.
	added fields to windowSubclassPair to accomodate this.
	added new function restoreWindow() to implement this.
	call restoreWindow() from cleanUp().
	changed arguments to removeDecorations() to include pointer to
	windowSubclassPair.  needed to store information for later
	use in restoring window.
	Revision 1.4  1997/10/12 00:22:22  doomer
	fixed a bug where DllMain would return FALSE in every case except
	process attach.  Prevented the DLL from loading.
	Revision 1.3  1997/09/08 23:50:50  doomer
	documentation.
	Revision 1.2  1997/08/25 00:50:46  doomer
	am using hot keys instead of a keyboard hook to trap window
	navigation key strokes.  Necessitated additional manifest constants,
	string table entries, and atoms.  Removed the keyboard hook and
	associated stuff.
	Revision 1.1  1997/08/17 04:58:12  doomer
	Initial revision
*********************************************************************/