#include "stdafx.h"
#include "CWHPaccess.h"

using namespace Ooganizer;
//////////////////////////////////////////////////////////////////////
//******************************************************************** 
// Global variables - Shared Data Segment (Shared across all instances 
//                    of this dll!)
//******************************************************************** 
//////////////////////////////////////////////////////////////////////
#pragma data_seg( ".CWHP" )
HHOOK CWHPaccess::hHook = NULL;
HookWndItem CWHPaccess::HList[MAX_PATH] = {NULL,NULL,NULL,NULL};
UINT CWHPaccess::HListI = 0;
wchar_t CWHPaccess::ALLOWED_PROCESS_NAMES[MAX_PATH][MAX_PATH] = {0};
UINT CWHPaccess::NUMBER_OF_ALLOWED_PROCESS_NAMES = 0;
wchar_t CWHPaccess::ALLOWED_WINDOW_TITLES[MAX_PATH][MAX_PATH] = {0};
UINT CWHPaccess::NUMBER_OF_ALLOWED_WINDOW_TITLES = 0;
wchar_t CWHPaccess::ALLOWED_WINDOW_CLASSES[MAX_PATH][MAX_PATH] = {0};
UINT CWHPaccess::NUMBER_OF_ALLOWED_WINDOW_CLASSES = 0;
UINT CWHPaccess::nLoggingDetail = LOGGING_NONE;
wchar_t CWHPaccess::LoggingPath[MAX_PATH] = {0};
#pragma data_seg()
#pragma comment( linker, "/SECTION:.CWHP,rws" )
//////////////////////////////////////////////////////////////////////
// Constructor / Destructor
//////////////////////////////////////////////////////////////////////
CWHPaccess::CWHPaccess()
{
	InitializeCriticalSection(&cs);
}
CWHPaccess::~CWHPaccess()
{
	DeleteCriticalSection(&cs);
}
// Set/Get hHook
void CWHPaccess::set_hHook(HHOOK hook)
{	
	EnterCS();
	hHook = hook;	
	LeaveCS();
}
HHOOK CWHPaccess::get_hHook()
{	
	return hHook;
}
// Public CRITICAL_SECTION Accessors
void CWHPaccess::EnterCS()
{	
	EnterCriticalSection(&cs);
}
void CWHPaccess::LeaveCS()
{	
	LeaveCriticalSection(&cs);
}
//////////////////////////////////////////////////////////////////////
// Func: ClearHookItem()
// Desc: Clears a single Hook Item
//////////////////////////////////////////////////////////////////////
void CWHPaccess::ClearHookItem(UINT nItem)
{
	if((nItem < 0) || (nItem >= MAX_PATH))
		return;

	HList[nItem].hWnd = NULL;
	HList[nItem].DefWndProc = NULL;
	HList[nItem].HookWndProc = NULL;
	HList[nItem].wpfcaller = NULL;
}
//////////////////////////////////////////////////////////////////////
// Func: ClearHookSData()
// Desc: Clears all the data stored in the Shared DS segment's Hook List
//////////////////////////////////////////////////////////////////////
void CWHPaccess::ClearHookSData()
{	
	EnterCS();
	hHook = NULL;
	HListI = 0;

	for (int i=0; i < MAX_PATH; ++i)
		ClearHookItem(i);

	LeaveCS();
}
//////////////////////////////////////////////////////////////////////
// Func: InsertHookedWndItem()
// Desc: Inserts a HookWndItem into the Shared DS's HookedList
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::InsertHookedWndItem(HookWndItem &Item)
{	
	BOOL bRetVal = FALSE;
	EnterCS();
	for (UINT i = 0;i < MAX_PATH; ++i)
	{
		if(HList[i].hWnd == NULL)
		{																
			HList[i] = Item;

			log(LOGGING_DEBUG, L"Inserting HookedItem into DS index = %i", i);
			// Keep track of the list top index *performance*
			if(i > HListI) 
			{				
				HListI = i;
				log(LOGGING_DEBUG, L"Inserting HookedItem setting HListI = %i", HListI);
			}
			bRetVal = TRUE;
			break;
		}
	}	
	LeaveCS();

	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: FindHookedWnd()
// Desc: Finds Inserts a HookWndItem into the Shared DS's HookedList
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::FindHookedWnd(HWND hWnd)
{
	BOOL bRetVal = FALSE;

	EnterCS();
	for (UINT i = 0;i <= HListI;++i)
	{
		if(HList[i].hWnd == hWnd)
		{				
			bRetVal = TRUE;
			break;
		}		
	}	
	LeaveCS();

	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: GetHookedWndItem()
// Desc: Returns a matchin HookWndItem (.hWnd will be NULL if not found)
//////////////////////////////////////////////////////////////////////
HookWndItem CWHPaccess::GetHookedWndItem(HWND hWnd)
{
	BLANK_HookWndItem(retVal);

	EnterCS();
	for (UINT i = 0;i <= HListI;++i)
	{
		if(HList[i].hWnd == hWnd)
		{			
			retVal = HList[i];
		}
	}
	LeaveCS();
	
	return(retVal);
}
//////////////////////////////////////////////////////////////////////
// Func: GetHookedWindowListNSize()
// Desc: Use this to get a copy of the hooked window buffer and size in the Shared DS
//////////////////////////////////////////////////////////////////////
void CWHPaccess::GetHookedWindowListNSize(int* nbuf, int* nsize)
{
	EnterCS();

	// write out the size
	*nsize = HListI;

	for (UINT i = 0;i <= HListI;++i)
	{
		// write out the actual buffer
		*(nbuf + i) = (int) HList[i].hWnd;
	}

	LeaveCS();
}
//////////////////////////////////////////////////////////////////////
// Func: SetHookedWndItem()
// Desc: Use this to overwrite Hook information for a window in the Shared DS
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::SetHookedWndItem(HWND hWnd, HookWndItem& Item)
{
	BOOL bRetVal = FALSE;
	EnterCS();
	for (UINT i = 0;i <= HListI;++i)
	{
		if((HList[i].hWnd == hWnd) && 
			(hWnd == Item.hWnd))
		{			
			HList[i] = Item;
			bRetVal = TRUE;
		}
	}
	LeaveCS();
	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: DeleteHookedWnd()
// Desc: Finds Inserts a HookWndItem into the Shared DS's HookedList
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::DeleteHookedWnd(HWND hWnd)
{

	BOOL retVal = FALSE;
	EnterCS();
	// Is it the Last Item in the list?
	if(HList[HListI].hWnd == hWnd)
	{		
		ClearHookItem(HListI);
		if(HListI > 0) 
		{
			HListI = HListI - 1;			
			log(LOGGING_DEBUG, L"DeleteHookedWnd HListI set to %i", HListI);
		}

		retVal = TRUE;
	}
	else
	{
		for (UINT i = 0; i <= HListI; ++i)
		{
			if(HList[i].hWnd == hWnd)
			{	
				ClearHookItem(i);
				deltaListTopI(i);
				retVal = TRUE;
				break;
			}
		}
	}
	LeaveCS();

	return retVal;
}
//////////////////////////////////////////////////////////////////////
// Func: deltaListTopI()
// Desc: *for performance * adjusts the Top index responding to a delete
//////////////////////////////////////////////////////////////////////
void CWHPaccess::deltaListTopI(int deletedIndex)
{	
	UINT i;

	EnterCS();
	for(i = deletedIndex + 1; i <= HListI; ++i)
	{
		if(HList[i].hWnd == NULL)
		{
			continue;
		}
		break;	
	}
	if(i > HListI)
	{
		if(deletedIndex > 0)
		{
			HListI = deletedIndex - 1;
			log(LOGGING_DEBUG, L"deltaListTopI HListI set to %i", HListI);
		}
		else
		{
			log(LOGGING_DEBUG, L"deltaListTopI HListI set to %i", HListI);
			HListI = 0;
		}				
	}	
	LeaveCS();
}
//////////////////////////////////////////////////////////////////////
// Func: AddAllowedProcessName()
// Desc: Add Allowed Process Name
//////////////////////////////////////////////////////////////////////
void CWHPaccess::AddAllowedProcessName(wchar_t* strProcessNameInUpperCase)
{
	if(strProcessNameInUpperCase)
	{
		EnterCS();
		int i = NUMBER_OF_ALLOWED_PROCESS_NAMES;
		lstrcpyn(ALLOWED_PROCESS_NAMES[i], strProcessNameInUpperCase, MAX_PATH - 1);		
		NUMBER_OF_ALLOWED_PROCESS_NAMES = i + 1;
		LeaveCS();

		log(LOGGING_DEBUG, L"Allowing Process %s", strProcessNameInUpperCase);
	}

}
//////////////////////////////////////////////////////////////////////
// Func: IsAllowedProcessName()
// Desc: Find Allowed Process Name
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::IsAllowedProcessName(wchar_t* strProcessNameInUpperCase)
{
	BOOL bRetVal = FALSE;
	if(strProcessNameInUpperCase)
	{
		EnterCS();
		for (UINT i = 0; i < NUMBER_OF_ALLOWED_PROCESS_NAMES; ++i)
		{
			if(wcsstr(strProcessNameInUpperCase, ALLOWED_PROCESS_NAMES[i]))
			{
				bRetVal = TRUE;
				break;
			}
		}
		LeaveCS();
	}	
	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: AddAllowedApplication()
// Desc: Add Allowed Windows Titles
//////////////////////////////////////////////////////////////////////
void CWHPaccess::AddAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase)
{
	if(strWindowsTitleInUpperCase)
	{
		EnterCS();
		int i = NUMBER_OF_ALLOWED_WINDOW_TITLES;
		lstrcpyn(ALLOWED_WINDOW_TITLES[i], strWindowsTitleInUpperCase, MAX_PATH - 1);
		NUMBER_OF_ALLOWED_WINDOW_TITLES = i + 1;
		LeaveCS();

		log(LOGGING_DEBUG, L"Allowing Window %s", strWindowsTitleInUpperCase);
	}
}
//////////////////////////////////////////////////////////////////////
// Func: IsAllowedWindowsTitle()
// Desc: Find Allowed Window Title
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::IsAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase)
{
	BOOL bRetVal = FALSE;
	if(strWindowsTitleInUpperCase)
	{
		EnterCS();
		for (UINT i = 0; i < NUMBER_OF_ALLOWED_WINDOW_TITLES; ++i)
		{
			if(wcsstr(strWindowsTitleInUpperCase, ALLOWED_WINDOW_TITLES[i]))
			{
				bRetVal = TRUE;
				break;
			}
		}
		LeaveCS();
	}	
	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: AddAllowedWindowsClass()
// Desc: Add Allowed Windows Class
//////////////////////////////////////////////////////////////////////
void CWHPaccess::AddAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase)
{
	if(strWindowsClassInUpperCase)
	{
		EnterCS();
		int i = NUMBER_OF_ALLOWED_WINDOW_CLASSES;	
		lstrcpyn(ALLOWED_WINDOW_CLASSES[i], strWindowsClassInUpperCase, MAX_PATH - 1);
		NUMBER_OF_ALLOWED_WINDOW_CLASSES = i + 1;
		LeaveCS();

		log(LOGGING_DEBUG, L"Allowing Window Class %s", strWindowsClassInUpperCase);
	}
}
//////////////////////////////////////////////////////////////////////
// Func: IsAllowedWindowsClass()
// Desc: Find Allowed Window Class
//////////////////////////////////////////////////////////////////////
BOOL CWHPaccess::IsAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase)
{
	BOOL bRetVal = FALSE;
	if(strWindowsClassInUpperCase)
	{
		EnterCS();
		for (UINT i = 0; i < NUMBER_OF_ALLOWED_WINDOW_CLASSES; ++i)
		{
			if(wcsstr(strWindowsClassInUpperCase, ALLOWED_WINDOW_CLASSES[i]))
			{
				bRetVal = TRUE;
				break;
			}
		}
		LeaveCS();
	}	
	return bRetVal;
}
//////////////////////////////////////////////////////////////////////
// Func: SetLoggingDetail()
// Desc: Allows us to set a global used by all button hooks to log
//////////////////////////////////////////////////////////////////////
void CWHPaccess::SetLoggingDetail(LoggingDetail nLoggingDetailSetting)
{
	EnterCS();
	nLoggingDetail = nLoggingDetailSetting;
	LeaveCS();
}
//////////////////////////////////////////////////////////////////////
// Desc: Returns the Detail of our Logging (high, medium, low, or none)
//////////////////////////////////////////////////////////////////////
LoggingDetail CWHPaccess::GetLoggingDetail()
{
	return (static_cast<LoggingDetail>(nLoggingDetail));
}
//////////////////////////////////////////////////////////////////////
// Desc: Get Directory location where we should log to
//////////////////////////////////////////////////////////////////////
wchar_t* CWHPaccess::GetLogPath()
{
	return reinterpret_cast<wchar_t*>(&LoggingPath);
}
//////////////////////////////////////////////////////////////////////
// Desc: Set Directory location where we should log to
//////////////////////////////////////////////////////////////////////
void CWHPaccess::SetLogPath(wchar_t* buf)
{
	EnterCS();
	lstrcpyn(LoggingPath,buf,MAX_PATH - 1);
	EnterCS();
}