반응형

MyService 로그램 용법

1. 비스 관 령어

 

  • 주요 기
  • 자동 시작 비스로 설치
  • 5초마다 상태 로
  • Ctrl+C로 버그 모드 종료 가능
     
  • 디버그 모드
  • 개발/테스트   -d  옵션으로 콘솔에서 직접 실행 가능
  • 로그가 콘솔에 출력
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable: 4819)
#pragma warning(disable: 4100)

#include <windows.h>
#include <tchar.h>
#include <winsvc.h>
#include <iostream>
#include <fstream>
#include <chrono>
#include <ctime>
#include <string>
#include <filesystem>

// 상수 정의
#define SERVICE_NAME _T("MyService")
#define SERVICE_DISPLAY_NAME _T("My Service")
#define SERVICE_DESC _T("My Service Description")
#define LOG_FILE "c:\\mysvc.log"

// 전역 변수
static bool g_debug_mode = false;
static std::ofstream g_log_file;
static SERVICE_STATUS_HANDLE g_ssh = NULL;
static HANDLE g_stop_event = NULL;

// 유니코드 매크로
#ifdef UNICODE
#define tprintf wprintf
#define tstring std::wstring
#else
#define tprintf printf
#define tstring std::string
#endif

// 함수 선언
void MySetStatus(DWORD dstatus, DWORD daccept);
void ServiceHandler(DWORD dwcontrol);
void ServiceHandlerEx(DWORD dwcontrol, DWORD dweventtype, LPVOID lpeventdata, LPVOID lpcontext);
void ServiceMain();
VOID WINAPI ServiceMainProc(DWORD argc, LPTSTR* argv);
bool InstallService();
bool UninstallService();
BOOL MyStartService(tstring Name);
bool StopService();
BOOL WINAPI DebugConsoleHandler(DWORD signal);
bool KillService();

// 로깅 함수
void LogMessage(const std::string& message) {
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    std::string timestamp = std::ctime(&time);
    timestamp.pop_back();

    std::string formatted_msg = "[" + timestamp + "] " + message + "\n";

    if (g_debug_mode) {
        std::cout << formatted_msg;
    }
    
    if (g_log_file.is_open()) {
        g_log_file << formatted_msg;
        g_log_file.flush();
    }
}

// 서비스 상태 관리 함수
void MySetStatus(DWORD dstatus, DWORD daccept) {
    SERVICE_STATUS ss = { 0, };
    if (!g_ssh) {
        LogMessage("MySetStatus: ERR status handle is null!");
        return;
    }
    ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ss.dwCurrentState = dstatus;
    ss.dwControlsAccepted = daccept;
    ss.dwWin32ExitCode = 10 * 1000;
    SetServiceStatus(g_ssh, &ss);
}

// 서비스 이벤트 핸들러
void ServiceHandler(DWORD dwcontrol) {
    LogMessage("ServiceHandler: control=" + std::to_string(dwcontrol));
    switch (dwcontrol) {
    case SERVICE_CONTROL_STOP:
        LogMessage("SERVICE_CONTROL_STOP received");
        MySetStatus(SERVICE_STOP_PENDING, SERVICE_ACCEPT_STOP);
        SetEvent(g_stop_event);
        break;
    default:
        MySetStatus(dwcontrol, SERVICE_ACCEPT_STOP);
        break;
    }
}

void ServiceHandlerEx(DWORD dwcontrol, DWORD dweventtype, LPVOID lpeventdata, LPVOID lpcontext) {
    LogMessage("ServiceHandlerEx: control=" + std::to_string(dwcontrol));
    switch (dwcontrol) {
    case SERVICE_CONTROL_SESSIONCHANGE:
        LogMessage("ServiceHandlerEx: session change");
        break;
    default:
        ServiceHandler(dwcontrol);
        break;
    }
}

// 서비스 메인 함수
void ServiceMain() {
    while (WaitForSingleObject(g_stop_event, 500) == WAIT_TIMEOUT) {
        LogMessage("Service is running...");
    }

    LogMessage("ServiceMain: End");
    if (!g_debug_mode) {
        MySetStatus(SERVICE_STOPPED, 0);
    }

    if (g_debug_mode) {
        CloseHandle(g_stop_event);
    }
}

VOID WINAPI ServiceMainProc(DWORD argc, LPTSTR* argv) {
    g_log_file.open(LOG_FILE, std::ios::app);
    LogMessage("Service started");

    g_ssh = RegisterServiceCtrlHandlerEx(SERVICE_NAME, (LPHANDLER_FUNCTION_EX)ServiceHandlerEx, NULL);
    LogMessage("ServiceMainProc: g_ssh=" + std::to_string((uint64_t)g_ssh));
    if (!g_ssh) {
        LogMessage("Failed to register service control handler");
        g_log_file.close();
        return;
    }

    MySetStatus(SERVICE_START_PENDING, 0);

    if (!g_stop_event) {
        g_stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!g_stop_event) {
            MySetStatus(SERVICE_STOPPED, 0);
            g_log_file.close();
            return;
        }
    }

    MySetStatus(SERVICE_RUNNING, SERVICE_ACCEPT_STOP);
    ServiceMain();
    g_log_file.close();
}

// 서비스 관리 함수들
bool InstallService() {
    SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
    if (!scm) return false;

    TCHAR path[MAX_PATH];
    GetModuleFileName(NULL, path, MAX_PATH);
    _tcscat_s(path, _T(" -svc"));

    SC_HANDLE service = CreateService(
        scm, SERVICE_NAME, SERVICE_DISPLAY_NAME,
        SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
        SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path,
        NULL, NULL, NULL, NULL, NULL);

    if (service) {
        SERVICE_DESCRIPTION sd = {const_cast<LPTSTR>(SERVICE_DESC)};
        ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd);
        CloseServiceHandle(service);
    }
    CloseServiceHandle(scm);
    return service != NULL;
}

bool UninstallService() {
    SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!scm) return false;

    SC_HANDLE service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS);
    if (!service) {
        CloseServiceHandle(scm);
        return false;
    }

    SERVICE_STATUS status;
    ControlService(service, SERVICE_CONTROL_STOP, &status);
    bool result = DeleteService(service);

    CloseServiceHandle(service);
    CloseServiceHandle(scm);
    return result;
}

BOOL MyStartService(tstring Name) {
    SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!schSCManager) {
        DWORD err = GetLastError();
        LogMessage("OpenSCManager failed. Error: " + std::to_string(err));
        return FALSE;
    }

    SC_HANDLE schService = OpenService(schSCManager, Name.c_str(), SERVICE_START | SERVICE_QUERY_STATUS);
    if (!schService) {
        DWORD err = GetLastError();
        LogMessage("OpenService failed. Error: " + std::to_string(err));
        CloseServiceHandle(schSCManager);
        return FALSE;
    }

    // 서비스 상태 확인
    SERVICE_STATUS status;
    if (QueryServiceStatus(schService, &status)) {
        if (status.dwCurrentState == SERVICE_RUNNING) {
            LogMessage("Service is already running");
            CloseServiceHandle(schService);
            CloseServiceHandle(schSCManager);
            return TRUE;
        }
    }

    // 서비스 시작
    if (!StartService(schService, 0, NULL)) {
        DWORD err = GetLastError();
        if (err == ERROR_SERVICE_ALREADY_RUNNING) {
            LogMessage("Service is already running");
            CloseServiceHandle(schService);
            CloseServiceHandle(schSCManager);
            return TRUE;
        }
        LogMessage("StartService failed. Error: " + std::to_string(err));
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return FALSE;
    }

    // 서비스가 실제로 시작될 때까지 대기
    int retries = 0;
    while (retries < 10) {  // 최대 10초 대기
        if (QueryServiceStatus(schService, &status)) {
            if (status.dwCurrentState == SERVICE_RUNNING) {
                LogMessage("Service started successfully");
                CloseServiceHandle(schService);
                CloseServiceHandle(schSCManager);
                return TRUE;
            }
            if (status.dwCurrentState == SERVICE_STOPPED) {
                LogMessage("Service failed to start");
                break;
            }
        }
        Sleep(1000);
        retries++;
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
    return FALSE;
}

bool StopService() {
    SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!scm) return false;

    SC_HANDLE service = OpenService(scm, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
    if (!service) {
        CloseServiceHandle(scm);
        return false;
    }

    SERVICE_STATUS status;
    bool result = ControlService(service, SERVICE_CONTROL_STOP, &status);
    
    // 서비스가 완전히 중지될 때까지 대기
    if (result) {
        while (QueryServiceStatus(service, &status)) {
            if (status.dwCurrentState == SERVICE_STOPPED) {
                break;
            }
            Sleep(1000);
        }
    }

    CloseServiceHandle(service);
    CloseServiceHandle(scm);
    return result;
}

// 디버그 모드 핸들러
BOOL WINAPI DebugConsoleHandler(DWORD signal) {
    if (signal == CTRL_C_EVENT || signal == CTRL_BREAK_EVENT) {
        LogMessage("Debug mode stop requested");
        if (g_stop_event) {
            SetEvent(g_stop_event);
        }
        return TRUE;
    }
    return FALSE;
}

// 서비스 강제 종료 함수 구현
bool KillService() {
    SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!scm) {
        LogMessage("OpenSCManager failed in KillService");
        return false;
    }

    SC_HANDLE service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS);
    if (!service) {
        LogMessage("OpenService failed in KillService");
        CloseServiceHandle(scm);
        return false;
    }

    // 현재 서비스 상태 확인
    SERVICE_STATUS status = { 0 };
    if (!QueryServiceStatus(service, &status)) {
        LogMessage("QueryServiceStatus failed in KillService");
        CloseServiceHandle(service);
        CloseServiceHandle(scm);
        return false;
    }

    // 서비스가 이미 중지 상태면 종료
    if (status.dwCurrentState == SERVICE_STOPPED) {
        LogMessage("Service is already stopped");
        CloseServiceHandle(service);
        CloseServiceHandle(scm);
        return true;
    }

    // 서비스 강제 종료 후 상태를 STOPPED로 변경
    LogMessage("Forcing service to stop state");
    memset(&status, 0, sizeof(SERVICE_STATUS));
    status.dwCurrentState = SERVICE_STOPPED;
    ControlService(service, SERVICE_CONTROL_STOP, &status);

    CloseServiceHandle(service);
    CloseServiceHandle(scm);
    return true;
}

// 메인 함수
int main(int argc, char* argv[]) {
    if (argc > 1) {
        if (strcmp(argv[1], "-i") == 0) {
            return InstallService() ? 0 : 1;
        }
        else if (strcmp(argv[1], "-r") == 0) {
            return MyStartService(SERVICE_NAME) ? 0 : 1;
        }
        else if (strcmp(argv[1], "-s") == 0) {
            return StopService() ? 0 : 1;
        }
        else if (strcmp(argv[1], "-u") == 0) {
            return UninstallService() ? 0 : 1;
        }
        else if (strcmp(argv[1], "-d") == 0) {
            g_debug_mode = true;
            SetConsoleCtrlHandler(DebugConsoleHandler, TRUE);
            g_log_file.open(LOG_FILE, std::ios::app);
            LogMessage("Debug mode started");

            g_stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
            if (!g_stop_event) {
                g_log_file.close();
                return 1;
            }
            ServiceMain();
            g_log_file.close();
            return 0;
        }
        else if (strcmp(argv[1], "-svc") == 0) {
            SERVICE_TABLE_ENTRY serviceTable[] = {
                {const_cast<LPTSTR>(SERVICE_NAME), ServiceMainProc},
                {NULL, NULL}
            };
            return StartServiceCtrlDispatcher(serviceTable) ? 0 : 1;
        }
        else if (strcmp(argv[1], "-k") == 0) {
            return KillService() ? 0 : 1;
        }
    }
    return 0;
}

 

 

 

 

 

+ Recent posts