#include "stdafx.h"
#include "resource.h"
#include "FWatchApp.hpp"

#include "ServiceEntry.hpp"

// サービス用変数
namespace {
	SERVICE_STATUS          ServiceStatus; 
	SERVICE_STATUS_HANDLE   ServiceStatusHandle; 
	LPTSTR lpszServiceName = _T("SeraphyFWatch");
	LPTSTR lpszDisplayName = _T("SeraphyFWatch");

	bool g_bWindowsNT;						// WindowsNTフラグ
}

// サービス用プロトタイプ
VOID WINAPI ServiceStartProc  (DWORD argc, LPTSTR *argv); 
VOID WINAPI ServiceCtrlHandler(DWORD opcode); 

/////////////////////////////////////////////////////////////////////////////
// サービスルーチン

BOOL ServiceInit()
{
	g_bWindowsNT = false;
	OSVERSIONINFO osv = {0};
	osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (GetVersionEx(&osv)) {
		if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
			g_bWindowsNT = true;
		}
	}
	return g_bWindowsNT;
}

void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
	switch(Opcode) 
	{ 
		case SERVICE_CONTROL_PAUSE:
			app.getCL().ReleaseAllThreads();
			ServiceStatus.dwCurrentState = SERVICE_PAUSED; 
			break; 
 
		case SERVICE_CONTROL_CONTINUE: 
			app.getCL().LoadInfData(app.getInfPath());
			ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
			break; 
 
		case SERVICE_CONTROL_STOP: 
			ServiceStatus.dwWin32ExitCode = 0; 
			ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
			ServiceStatus.dwCheckPoint    = 0; 
			ServiceStatus.dwWaitHint      = 0; 
			SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
			return; 
 
		case SERVICE_CONTROL_INTERROGATE: 
			break; 
		default:
			break;
    } 
    SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    return; 
}

void WINAPI ServiceStartProc(DWORD, LPTSTR *)
{
	// サービス開始設定
	ServiceStatusHandle = RegisterServiceCtrlHandler(lpszServiceName, ServiceCtrlHandler);
    if (ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0) {
        return; 
    }

    ServiceStatus.dwServiceType			= SERVICE_WIN32; 
    ServiceStatus.dwControlsAccepted	= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
	ServiceStatus.dwCurrentState		= SERVICE_RUNNING;//SERVICE_STOPPED_PENDING; 
    ServiceStatus.dwWin32ExitCode		= 0; 
    ServiceStatus.dwServiceSpecificExitCode = 0; 
    ServiceStatus.dwCheckPoint			= 0; 
    ServiceStatus.dwWaitHint			= 0; 
    SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    return; 
} 

int RegistService()
{
	if ( !g_bWindowsNT) {
		// Windows9xでは登録の意味がない
		app.showMessageBox(MB_ICONERROR|MB_OK, NULL, IDS_SERVICE_W9X);
		return 0;
	}

	// サービスをサービスコントロールマネージャに登録します
	SC_HANDLE schSCManager = OpenSCManager(
		NULL,                    // local machine 
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 
	if (schSCManager) {
		// 実行ファイル名の取得
		TCHAR lpszBinaryPathName[MAX_PATH * 2] = {0};
		GetModuleFileName(NULL, lpszBinaryPathName, MAX_PATH);
		lstrcat(lpszBinaryPathName, _T(" /runservice"));

		// 登録
		SC_HANDLE schService = CreateService( 
			schSCManager,              // SCManager database 
			lpszServiceName,           // name of service 
			lpszDisplayName,           // service name to display 
			SERVICE_ALL_ACCESS,        // desired access 
			SERVICE_WIN32_OWN_PROCESS, // service type 
			SERVICE_DEMAND_START,      // start type 
			SERVICE_ERROR_NORMAL,      // error control type 
			lpszBinaryPathName,        // service's binary 
			NULL,                      // no load ordering group 
			NULL,                      // no tag identifier 
			NULL,                      // no dependencies 
			NULL,                      // LocalSystem account 
			NULL);                     // no password 
		// メッセージ
		if (schService) {
			app.showMessageBox(MB_ICONINFORMATION | MB_OK, NULL, IDS_MAINPROC_INSTALLSERVICE);
		}
		else {
			DWORD err = GetLastError();
			if (err == ERROR_SERVICE_EXISTS || err == ERROR_DUP_NAME) {
				app.showMessageBox(MB_ICONERROR | MB_OK, NULL, IDS_MAINPROC_SERVICEEXIST);
			}
			else {
				app.showMessageBox(MB_ICONERROR | MB_OK, NULL, IDS_MAINPROC_INSTALLFAIL);
			}
		}
		// 後始末
		CloseServiceHandle(schService); 
		CloseServiceHandle(schSCManager);
	}
	return 0;
}

int UnregistService()
{
	if ( !g_bWindowsNT) {
		// Windows9xでは解除の意味がない
		app.showMessageBox(MB_ICONERROR | MB_OK, NULL, IDS_SERVICE_W9X);
		return 0;
	}

	// サービスをサービスコントロールマネージャに登録解除します
	SC_HANDLE schSCManager = OpenSCManager(
		NULL,                    // local machine 
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 
	if (schSCManager) {
		// 登録解除
		SC_HANDLE schService = OpenService(
			schSCManager,              // SCManager database
			lpszServiceName,           // name of service
			SERVICE_ALL_ACCESS);        // desired access
		if (schService) {
			if (DeleteService(schService)) {
				app.showMessageBox(MB_ICONINFORMATION | MB_OK, NULL, IDS_MAINPROC_UNINSTALLSERVICE);
			}
			else {
				app.showMessageBox(MB_ICONERROR | MB_OK, NULL, IDS_MAINPROC_UNINSTALLFAIL);
			}
		}
	}
	return 0;
}

BOOL IsRegistService(BOOL& bStartService)
{
	if ( !g_bWindowsNT) {
		return FALSE;
	}

	BOOL ret = false;
	bStartService = false;
	SC_HANDLE schSCManager = OpenSCManager(
		NULL,                    // local machine 
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 
	if (schSCManager) {
		SC_HANDLE schService = OpenService(schSCManager, lpszServiceName, SERVICE_QUERY_STATUS |GENERIC_READ);
		if (schService) {
			SERVICE_STATUS sst = {0};
			if (QueryServiceStatus(schService, &sst)) {
				if (sst.dwCurrentState == SERVICE_RUNNING ||
					sst.dwCurrentState == SERVICE_PAUSED) {
					// サービスは現在動作中である
					bStartService = true;
				}
			}
			CloseServiceHandle(schService); 
			// サービスはインストールされている
			ret = true;
		}
		CloseServiceHandle(schSCManager);
	}
	return ret;
}

BOOL StartService()
{
	// サービスの登録を行います
    SERVICE_TABLE_ENTRY   ServiceDispatchTable[] = { 
        { lpszServiceName, ServiceStartProc  }, 
        { NULL,            NULL              }
	};
	return ::StartServiceCtrlDispatcher(ServiceDispatchTable);
}

void ServiceReStart()
{
	// 再起動
	app.getCL().SaveInfData(app.getInfPath());
	app.getCL().ReleaseAllThreads();
	app.getCL().LoadInfData(app.getInfPath());
	//
	// サービスコントロールマネージャの取得と、サービスの開始
	SC_HANDLE schSCManager = OpenSCManager(
		NULL,                    // local machine 
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);	 // full access rights 
	if (schSCManager) { 
		
		SC_HANDLE schService = OpenService(schSCManager, lpszServiceName, SERVICE_START | SERVICE_STOP | GENERIC_EXECUTE);
		if (schService) {
			LPCTSTR param[] = {app.getInfPath().c_str() ,NULL};
			if ( ! ::StartService(schService, 1, param)) {
				DWORD err = GetLastError();
				if (err == ERROR_SERVICE_ALREADY_RUNNING) {
					app.showMessageBox(MB_ICONERROR | MB_OK, lpszServiceName, IDS_SERVICE_RUNNING);
				}
				else if (err == ERROR_SERVICE_DISABLED) {
					app.showMessageBox(MB_ICONERROR | MB_OK, lpszServiceName, IDS_SERVICE_DISABLED);
				}
				else {
					app.showMessageBox(MB_ICONERROR | MB_OK, lpszServiceName, IDS_SERVICE_STARTERROR);
				}
			}
			else {
				app.showMessageBox(MB_ICONINFORMATION | MB_OK, lpszServiceName, IDS_SERVICE_START);
			}
			CloseServiceHandle(schService); 
		}
		CloseServiceHandle(schSCManager);
	}
}

void ServiceStop()
{
	// サービスコントロールマネージャの取得と、サービスの停止
	SC_HANDLE schSCManager = OpenSCManager(
			NULL,                    // local machine 
			NULL,                    // ServicesActive database 
			SC_MANAGER_ALL_ACCESS);  // full access rights 
	if (schSCManager) {  
		SC_HANDLE schService = OpenService(schSCManager, lpszServiceName, SERVICE_START | SERVICE_STOP | GENERIC_EXECUTE);
		if (schService) {
			SERVICE_STATUS sst;
			if ( !ControlService(schService, SERVICE_CONTROL_STOP, &sst)) {
				DWORD err = GetLastError();
				if (err != ERROR_SERVICE_NOT_ACTIVE) {
					app.showMessageBox(MB_ICONERROR | MB_OK, lpszServiceName, IDS_SERVICE_STOPERROR);
				}
			}
			else {
				app.showMessageBox(MB_ICONINFORMATION | MB_OK, lpszServiceName, IDS_SERVICE_STOP);
			}
			CloseServiceHandle(schService); 
		}
		CloseServiceHandle(schSCManager);
	}
}
