main.cpp 8.31 KB
/*  Copyright (C) 2010-2012  kaosu (qiupf2000@gmail.com)
 *  This file is part of the Interactive Text Hooker.

 *  Interactive Text Hooker is free software: you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ITH.h"
#include "host/host.h"
#include "host/hookman.h"
#include "host/settings.h"
#include "CustomFilter.h"
#include "profile/Profile.h"
#include "ProfileManager.h"

HINSTANCE hIns;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, DWORD nCmdShow, RECT *rc);
RECT window;
extern HWND hMainWnd; // windows.cpp
extern bool MonitorFlag; // ProfileManager.cpp
extern ProfileManager* pfman; // ProfileManager.cpp

extern "C" {
	BOOL IthInitSystemService();
	void IthCloseSystemService();
}

CustomFilter* uni_filter;
CustomFilter* mb_filter;
HookManager* man;
Settings* setman;
LONG split_time, cyclic_remove, global_filter;
LONG process_time, inject_delay, insert_delay,
auto_inject, auto_insert, clipboard_flag;

std::map<std::wstring, long> setting;

void RecordMBChar(WORD mb, PVOID f)
{
	auto filter = (pugi::xml_node*)f;
	DWORD m = mb;
	WCHAR buffer[16];
	std::swprintf(buffer, L"m%04X", m);
	filter->append_attribute(buffer) = L"0";
}

void RecordUniChar(WORD uni, PVOID f)
{
	auto filter = (pugi::xml_node*)f;
	DWORD m = uni;
	WCHAR buffer[16];
	std::swprintf(buffer, L"u%04X", m);
	filter->append_attribute(buffer) = L"0";
	std::wstring text = filter->text().get();
	text += (wchar_t)m;
	filter->text().set(text.c_str());
}

void SaveSettings()
{
	WINDOWPLACEMENT wndpl;
	wndpl.length = sizeof(WINDOWPLACEMENT);
	GetWindowPlacement(hMainWnd, &wndpl);
	setting[L"window_left"] = wndpl.rcNormalPosition.left;
	setting[L"window_right"] = wndpl.rcNormalPosition.right;
	setting[L"window_top"] = wndpl.rcNormalPosition.top;
	setting[L"window_bottom"] = wndpl.rcNormalPosition.bottom;
	setting[L"split_time"] = split_time;
	setting[L"process_time"] = process_time;
	setting[L"inject_delay"] = inject_delay;
	setting[L"insert_delay"] = insert_delay;
	setting[L"auto_inject"] = auto_inject;
	setting[L"auto_insert"] = auto_insert;
	setting[L"auto_copy"] = clipboard_flag;
	setting[L"auto_suppress"] = cyclic_remove;
	setting[L"global_filter"] = global_filter;

	UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
	if (hFile.get() != INVALID_HANDLE_VALUE)
	{
		FileWriter fw(hFile.get());
		pugi::xml_document doc;
		auto root = doc.root().append_child(L"ITH_Setting");
		for (auto it = setting.begin(); it != setting.end(); ++it)
			root.append_attribute(it->first.c_str()).set_value(it->second);
		auto filter = root.append_child(L"SingleCharFilter");
		filter.append_child(pugi::xml_node_type::node_pcdata);
		mb_filter->Traverse(RecordMBChar, &filter);
		uni_filter->Traverse(RecordUniChar, &filter);
		doc.save(fw);
	}
}

void DefaultSettings()
{
	setting[L"split_time"] = 200;
	setting[L"process_time"] = 50;
	setting[L"inject_delay"] = 3000;
	setting[L"insert_delay"] = 500;
	setting[L"auto_inject"] = 1;
	setting[L"auto_insert"] = 1;
	setting[L"auto_copy"] = 0;
	setting[L"auto_suppress"] = 0;
	setting[L"global_filter"] = 0;
	setting[L"window_left"] = 100;
	setting[L"window_right"] = 800;
	setting[L"window_top"] = 100;
	setting[L"window_bottom"] = 600;
}

void InitializeSettings()
{
	split_time = setting[L"split_time"];
	process_time = setting[L"process_time"];
	inject_delay = setting[L"inject_delay"];
	insert_delay = setting[L"insert_delay"];
	auto_inject = setting[L"auto_inject"];
	auto_insert = setting[L"auto_insert"];
	clipboard_flag = setting[L"auto_copy"];
	cyclic_remove = setting[L"auto_suppress"];
	global_filter = setting[L"global_filter"];
	window.left = setting[L"window_left"];
	window.right = setting[L"window_right"];
	window.top = setting[L"window_top"];
	window.bottom = setting[L"window_bottom"];

	if (auto_inject > 1)
		auto_inject = 1;
	if (auto_insert > 1)
		auto_insert = 1;
	if (clipboard_flag > 1)
		clipboard_flag = 1;
	if (cyclic_remove > 1)
		cyclic_remove = 1;

	if (window.right < window.left || window.right - window.left < 600)
		window.right = window.left + 600;
	if (window.bottom < window.top || window.bottom - window.top < 200)
		window.bottom = window.top + 200;
}

void LoadSettings()
{
	UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
	if (hFile.get() != INVALID_HANDLE_VALUE)
	{
		DWORD size = GetFileSize(hFile.get(), NULL);
		std::unique_ptr<char[]> buffer(new char[size]);
		ReadFile(hFile.get(), buffer.get(), size, &size, NULL);
		pugi::xml_document doc;
		auto result = doc.load_buffer_inplace(buffer.get(), size);
		if (!result)
			return;
		auto root = doc.root().child(L"ITH_Setting");
		for (auto attr = root.attributes_begin(); attr != root.attributes_end(); ++attr)
		{
			auto it = setting.find(attr->name());
			if (it != setting.end())
				it->second = std::stoul(attr->value());
		}
		auto filter = root.child(L"SingleCharFilter");
		if (filter)
		{
			for (auto attr = filter.attributes_begin(); attr != filter.attributes_end(); ++attr)
			{
				if (attr->name()[0] == L'm')
				{
					DWORD c = std::stoul(attr->name() + 1, NULL, 16);
					mb_filter->Insert(c & 0xFFFF);
				}
				else if (attr->name()[0] == L'u')
				{
					DWORD c = std::stoul(attr->name() + 1, NULL, 16);
					uni_filter->Insert(c & 0xFFFF);
				}
			}
			std::wstring filter_value = filter.text().get();
			for (auto it = filter_value.begin(); it != filter_value.end(); ++it)
			{
				WCHAR filter_unichar[2] = { *it, L'\0' };
				char filter_mbchar[4];
				WC_MB(filter_unichar, filter_mbchar, 4);
				mb_filter->Insert(*(WORD*)filter_mbchar);
				uni_filter->Insert(*it);
			}
		}
	}
}

extern LPCWSTR ClassName, ClassNameAdmin;
static WCHAR mutex[] = L"ITH_RUNNING";
DWORD FindITH()
{
	HWND hwnd = FindWindow(ClassName, ClassName);
	if (hwnd == NULL)
		hwnd = FindWindow(ClassName, ClassNameAdmin);
	if (hwnd)
	{
		ShowWindow(hwnd, SW_SHOWNORMAL);
		SetForegroundWindow(hwnd);
		return 0;
	}
	return 1;
}
LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo)
{
	wchar_t path_name[512]; // fully qualified path name
	WCHAR code[16];
	EXCEPTION_RECORD* rec = ExceptionInfo->ExceptionRecord;
	std::swprintf(code, L"%08X", rec->ExceptionCode);
	MEMORY_BASIC_INFORMATION info;
	if (VirtualQuery(rec->ExceptionAddress, &info, sizeof(info)))
	{
		if (GetModuleFileName((HMODULE)info.AllocationBase, path_name, 512))
		{
			LPWSTR name = wcsrchr(path_name, L'\\');
			if (name)
			{
				DWORD addr = (DWORD)rec->ExceptionAddress;
				std::swprintf(name, L"%s:%08X", name + 1, addr - (DWORD)info.AllocationBase);
				MessageBox(NULL, name, code, MB_OK);
				TerminateProcess(GetCurrentProcess(), 0);
			}
		}
	}
	std::swprintf(path_name, L"%08X", rec->ExceptionAddress);
	MessageBox(NULL, path_name, code, MB_OK);
	TerminateProcess(GetCurrentProcess(), 0);
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	InitCommonControls();
	if (!IthInitSystemService())
		TerminateProcess(GetCurrentProcess(), 0);
	CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING");
	if (Host_Open())
	{
		SetUnhandledExceptionFilter(UnhandledExcept);
		Host_GetHookManager(&man);
		Host_GetSettings(&setman);
		setman->splittingInterval = 200;
		MonitorFlag = true;
		pfman = new ProfileManager();
		mb_filter = new CustomFilter();
		uni_filter = new CustomFilter();
		DefaultSettings();
		LoadSettings();
		InitializeSettings();
		setman->splittingInterval = split_time;
		setman->clipboardFlag = clipboard_flag > 0;
		hIns = hInstance;
		MyRegisterClass(hIns);
		InitInstance(hIns, FALSE, &window);
		MSG msg;
		while (GetMessage(&msg, NULL, 0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		//delete mb_filter;
		//delete uni_filter;
		delete pfman;
		MonitorFlag = false;
		man = NULL;
	}
	else
	{
		FindITH();
	}
	Host_Close();
	IthCloseSystemService();
	TerminateProcess(GetCurrentProcess(), 0);
}