commit 4863c5a8774fe2a510b74c5d9e3617932d0b7683 Author: kdeng00 Date: Sat Dec 5 22:16:43 2020 -0500 First commit diff --git a/ServiceExample.sdf b/ServiceExample.sdf new file mode 100644 index 0000000..46c78eb Binary files /dev/null and b/ServiceExample.sdf differ diff --git a/ServiceExample.sln b/ServiceExample.sln new file mode 100644 index 0000000..38dd6ee --- /dev/null +++ b/ServiceExample.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServiceExample", "ServiceExample\ServiceExample.vcxproj", "{19AD11CD-7C72-41C6-B372-32A63C2EAB7A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {19AD11CD-7C72-41C6-B372-32A63C2EAB7A}.Debug|Win32.ActiveCfg = Debug|Win32 + {19AD11CD-7C72-41C6-B372-32A63C2EAB7A}.Debug|Win32.Build.0 = Debug|Win32 + {19AD11CD-7C72-41C6-B372-32A63C2EAB7A}.Release|Win32.ActiveCfg = Release|Win32 + {19AD11CD-7C72-41C6-B372-32A63C2EAB7A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ServiceExample/Main.cpp b/ServiceExample/Main.cpp new file mode 100644 index 0000000..801726f --- /dev/null +++ b/ServiceExample/Main.cpp @@ -0,0 +1,371 @@ +#include +#include +#include +#include + +#include +#include +#include + +#pragma comment(lib, "advapi32.lib") +#pragma comment(lib, "kernel32.lib") + +#include "Models.h" +#include "ServiceEntryPoint.hpp" +#include "ServiceControlHandler.hpp" + + +#define SVCNAME TEXT("ServiceExample") +// #define SERVICE_NAME _T("My Service Example") + +// service::ServiceControlHandler::g_ServiceStatus = {0}; +// SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; +// service::ServiceControlHandler::g_StatusHandle = nullptr; +SERVICE_STATUS g_ServiceStatus; + // static SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; +SERVICE_STATUS_HANDLE g_StatusHandle; + +HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE; + +// template +// VOID WINAPI ServiceMain(D, LStr *); +VOID ServiceInstall(void); +VOID WINAPI ServiceMain(DWORD, LPTSTR*); +VOID WINAPI ServiceCtrlHandler(DWORD); +// DWORD WINAPI ServiceWorkerThread(LPVOID lpParam); + +VOID ReportServiceStatus(DWORD, DWORD, DWORD); +VOID ServiceInit(DWORD, LPTSTR*); +VOID ServiceReportEvent(LPTSTR); + +DWORD WINAPI ServiceWorkerThread(LPVOID lpParam); + +// models::ServiceInfo<> service_info(L"Service Example"); +std::shared_ptr> service_info(new models::ServiceInfo<>(L"Service Example")); + + +#undef main + +// int main() +int _tmain(int argc, TCHAR *argv[]) +// int __cdel_tmain(int argc, TCHAR *argv[]) +{ + std::cout << "ServiceExample\n"; + + auto v = TEXT("sss"); + + // service::ServiceControlHandler::g_ServiceStatus = {0}; + // SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; + // service::ServiceControlHandler::g_StatusHandle = nullptr; + + /** + SERVICE_TABLE_ENTRY SERVICETABLE[] = + { + // { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, + { SVCNAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, + {nullptr, nullptr} + }; + */ + + // if (StartServiceCtr) + + if (lstrcmpi(argv[1], TEXT("install")) == 0) + { + ServiceInstall(); + + return -1; + } + + service::ServiceEntryPoint entry; + // models::ServiceInfo<> service_info(TEXT("ServiceExample")); + // models::ServiceInfo<> service_info(L"Service Example"); + + SERVICE_TABLE_ENTRY SERVICETABLE[] = + { + // { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, + // { SVCNAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, + // { service_info.service_name, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, + // { (const_cast(service_info.service_name)) , (LPSERVICE_MAIN_FUNCTION)entry.service_main }, + // { SVCNAME, (LPSERVICE_MAIN_FUNCTION)entry.service_main_start}, + { SVCNAME, (LPSERVICE_MAIN_FUNCTION)service::ServiceEntryPoint::service_main_start }, + { nullptr, nullptr }, + }; + + if (!StartServiceCtrlDispatcher(SERVICETABLE)) + { + auto func = reinterpret_cast(TEXT("StartServiceCtrlDispatcher")); + ServiceReportEvent(func); + } + + + return 0; +} + + + +VOID ServiceInstall() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + // TCHAR szPath[MAX_PATH]; + wchar_t buffer[MAX_PATH]; + + // if (!GetModuleFileName("", szPath, MAX_PATH)) + if (!GetModuleFileName(nullptr, buffer, MAX_PATH)) + { + std::cout << "Cannot install service " << GetLastError() << "\n"; + + return; + } + + // Get a handle to the SCM database. + + schSCManager = OpenSCManager( + NULL, // local computer + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + + if (NULL == schSCManager) + { + std::cout << "OpenSCManager failed " << GetLastError() << "\n"; + + return; + } + + // Create the service + + schService = CreateService( + schSCManager, // SCM database + SVCNAME, // name of service + SVCNAME, // 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 + // szPath, // path to service's binary + buffer, // path to service's binary + NULL, // no load ordering group + NULL, // no tag identifier + NULL, // no dependencies + NULL, // LocalSystem account + NULL); // no password + + if (schService == NULL) + { + // printf("CreateService failed (%d)\n", GetLastError()); + std::cout << "CreateService failed " << GetLastError() << "\n"; + + CloseServiceHandle(schSCManager); + return; + } + else + { + // printf("Service installed successfully\n"); + std::cout << "Service installed successfully\n"; + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +VOID ServiceReportEvent(LPTSTR szFunction) +{ + HANDLE hEventSource; + LPCTSTR lpszStrings[2]; + TCHAR Buffer[80]; + + hEventSource = RegisterEventSource(NULL, SVCNAME); + + if (NULL != hEventSource) + { + StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError()); + + lpszStrings[0] = SVCNAME; + lpszStrings[1] = Buffer; + + ReportEvent(hEventSource, // event log handle + EVENTLOG_ERROR_TYPE, // event type + 0, // event category + // SVC_ERROR, + SERVICE_ERROR_NORMAL, // event identifier + NULL, // no security identifier + 2, // size of lpszStrings array + 0, // no binary data + lpszStrings, // array of strings + NULL); // no binary data + + DeregisterEventSource(hEventSource); + } +} + + +VOID ReportServiceStatus(DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) +{ + static DWORD dwCheckPoint = 1; + + g_ServiceStatus.dwCurrentState = dwCurrentState; + g_ServiceStatus.dwWin32ExitCode = dwWin32ExitCode; + g_ServiceStatus.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + { + g_ServiceStatus.dwControlsAccepted = 0; + } + else + { + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + } + + if ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) + { + g_ServiceStatus.dwCheckPoint = 0; + } + else + { + g_ServiceStatus.dwCheckPoint = dwCheckPoint++; + } + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); +} + +VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl) +{ + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: + ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); + + SetEvent(g_ServiceStopEvent); + ReportServiceStatus(g_ServiceStatus.dwCurrentState, NO_ERROR, 0); + + return; + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } +} + + + + + +VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) +// template +// VOID WINAPI ServiceMain(D argc, LStr *argv) +{ + g_StatusHandle = RegisterServiceCtrlHandler( + SVCNAME, + ServiceCtrlHandler); + + if (!g_StatusHandle) + { + // Report the service event + return; + } + + + + // Tell the service controller we are starting + ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus)); + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwServiceSpecificExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + /* + * Perform tasks necessary to start the service here + */ + + // Create a service stop event to wait on later + g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (g_ServiceStopEvent == NULL) + { + // Error creating event + // Tell service controller we are stopped and exit + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = GetLastError(); + g_ServiceStatus.dwCheckPoint = 1; + + if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + return; + } + + + // Tell the service controller we are started + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + // Start a thread that will perform the main task of the service + HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL); + + // Wait until our worker thread exits signaling that the service needs to stop + WaitForSingleObject(hThread, INFINITE); + + + /* + * Perform any cleanup tasks + */ + + CloseHandle(g_ServiceStopEvent); + + // Tell the service controller we are stopped + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 3; + + if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } +} + +DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) +{ + // const auto some_file_path = "C:\\Users\\brahmix\\example_file.txt"; + const auto some_file_path = "C:\\example_file.txt"; + + while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) + { + std::fstream file(some_file_path, std::ios::out | std::ios::app); + + const auto content = "test"; + + file << content << "\n"; + + file.close(); + + Sleep(3000); + } + + + return ERROR_SUCCESS; +} + diff --git a/ServiceExample/Models.h b/ServiceExample/Models.h new file mode 100644 index 0000000..37e95db --- /dev/null +++ b/ServiceExample/Models.h @@ -0,0 +1,34 @@ +#ifndef MODELS_H_ +#define MODELS_H_ + +#include + + +namespace models +{ + template + class ServiceInfo + { + public: + ServiceInfo() + { + service_stop_event = INVALID_HANDLE_VALUE; + } + ServiceInfo(std::wstring &&name) : + service_name(const_cast(name.c_str())) + { + service_stop_event = INVALID_HANDLE_VALUE; + } + + wchar_t *service_name; + Status service_status; + StatusHandle service_handle; + Handle service_stop_event; + }; +} + +#endif \ No newline at end of file diff --git a/ServiceExample/ServiceControlHandler.hpp b/ServiceExample/ServiceControlHandler.hpp new file mode 100644 index 0000000..0fc07bb --- /dev/null +++ b/ServiceExample/ServiceControlHandler.hpp @@ -0,0 +1,86 @@ +#ifndef SERVICECONTROLHANDLER_H_ +#define SERVICECONTROLHANDLER_H_ + +#include + +#include +#include +#include + +#include "Models.h" + +namespace service +{ + class ServiceControlHandler + { + public: + template + static VOID WINAPI ServiceCtrlHandler(D ctrlCode) + { + extern std::shared_ptr> service_info; + + switch (ctrlCode) + { + case SERVICE_CONTROL_STOP: + // ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); + ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); + + SetEvent(service_info->service_stop_event); + // ReportServiceStatus(g_ServiceStatus.dwCurrentState, NO_ERROR, 0); + ReportServiceStatus(service_info->service_status.dwCurrentState, NO_ERROR, 0); + + return; + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } + } + // static SERVICE_STATUS g_ServiceStatus = {0}; + // static SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; + // static SERVICE_STATUS g_ServiceStatus; + // static SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; + // static SERVICE_STATUS_HANDLE g_StatusHandle; + + + + static VOID ReportServiceStatus(DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) + { + extern std::shared_ptr> service_info; + + static DWORD dwCheckPoint = 1; + + service_info->service_status.dwCurrentState = dwCurrentState; + service_info->service_status.dwWin32ExitCode = dwWin32ExitCode; + service_info->service_status.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + { + service_info->service_status.dwControlsAccepted = 0; + } + else + { + service_info->service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + } + + if ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) + { + service_info->service_status.dwCheckPoint = 0; + } + else + { + service_info->service_status.dwCheckPoint = dwCheckPoint++; + } + + // SetServiceStatus(g_StatusHandle, &service_info->service_status); + SetServiceStatus(service_info->service_handle, &service_info->service_status); + } + + private: + }; +} + +#endif \ No newline at end of file diff --git a/ServiceExample/ServiceEntryPoint.hpp b/ServiceExample/ServiceEntryPoint.hpp new file mode 100644 index 0000000..f742fcf --- /dev/null +++ b/ServiceExample/ServiceEntryPoint.hpp @@ -0,0 +1,230 @@ +#ifndef SERVICEENTRYPOINT_H_ +#define SERVICEENTRYPOINT_H_ + +#include +#include + +#include +#include +#include + +#include "Models.h" +#include "ServiceControlHandler.hpp" + +namespace service +{ + class ServiceEntryPoint + { + public: + ServiceEntryPoint() + { + initialize(); + } + + ServiceEntryPoint(std::wstring name) + { + // service_name = static_cast(name); + // service_name = name.c_str(); + initialize(); + } + + static VOID WINAPI service_main_start(DWORD argc, LPTSTR *argv) + { + // extern models::ServiceInfo<> service_info; + extern std::shared_ptr> service_info; + + + service_info->service_handle = RegisterServiceCtrlHandler( + // SVCNAME, + service_info->service_name, + // ServiceCtrlHandler); + service::ServiceControlHandler::ServiceCtrlHandler); + + if (!service_info->service_handle) + { + // Report the service event + return; + } + + + + // Tell the service controller we are starting + ZeroMemory(&service_info->service_status, sizeof(service_info->service_status)); + service_info->service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_info->service_status.dwControlsAccepted = 0; + service_info->service_status.dwCurrentState = SERVICE_START_PENDING; + service_info->service_status.dwWin32ExitCode = 0; + service_info->service_status.dwServiceSpecificExitCode = 0; + service_info->service_status.dwCheckPoint = 0; + + if (SetServiceStatus(service_info->service_handle, &service_info->service_status) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + /* + * Perform tasks necessary to start the service here + */ + + // Create a service stop event to wait on later + service_info->service_stop_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (service_info->service_stop_event == NULL) + { + // Error creating event + // Tell service controller we are stopped and exit + service_info->service_status.dwControlsAccepted = 0; + service_info->service_status.dwCurrentState = SERVICE_STOPPED; + service_info->service_status.dwWin32ExitCode = GetLastError(); + service_info->service_status.dwCheckPoint = 1; + + if (SetServiceStatus(service_info->service_handle, &service_info->service_status) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + return; + } + + + // Tell the service controller we are started + service_info->service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + service_info->service_status.dwCurrentState = SERVICE_RUNNING; + service_info->service_status.dwWin32ExitCode = 0; + service_info->service_status.dwCheckPoint = 0; + + if (SetServiceStatus(service_info->service_handle, &service_info->service_status) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + + // Start a thread that will perform the main task of the service + HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL); + + // Wait until our worker thread exits signaling that the service needs to stop + WaitForSingleObject(hThread, INFINITE); + + + /* + * Perform any cleanup tasks + */ + + CloseHandle(service_info->service_stop_event); + + // Tell the service controller we are stopped + service_info->service_status.dwControlsAccepted = 0; + service_info->service_status.dwCurrentState = SERVICE_STOPPED; + service_info->service_status.dwWin32ExitCode = 0; + service_info->service_status.dwCheckPoint = 3; + + if (SetServiceStatus(service_info->service_handle, &service_info->service_status) == FALSE) + { + OutputDebugString(_T( + "My Sample Service: ServiceMain: SetServiceStatus returned error")); + } + } + + + + static DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) + // static DWORD WINAPI ServiceWorkerThread(LPVOID lpParam, + // std::shared_ptr> service_info) + { + extern std::shared_ptr> service_info; + + // const auto some_file_path = "C:\\Users\\brahmix\\example_file.txt"; + const auto some_file_path = "C:\\example_file.txt"; + + // while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) + while (WaitForSingleObject(service_info->service_stop_event, 0) != WAIT_OBJECT_0) + { + std::fstream file(some_file_path, std::ios::out | std::ios::app); + + const auto content = "woof"; + + file << content << "\n"; + + file.close(); + + Sleep(3000); + } + + + return ERROR_SUCCESS; + } + + + template + // VOID ServiceReportEvent(LPTSTR szFunction) + VOID ServiceReportEvent(TStr szFunction) + { + // HANDLE hEventSource; + H hEventSource; + // LPCTSTR lpszStrings[2]; + CSTR lpszStrings[2]; + // TCHAR Buffer[80]; + CHR Buffer[80]; + + hEventSource = RegisterEventSource(NULL, this->service_info.service_name); + // hEventSource = RegisterEventSource(NULL, L("")); + + if (NULL != hEventSource) + { + StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError()); + + lpszStrings[0] = SVCNAME; + lpszStrings[1] = Buffer; + + ReportEvent(hEventSource, // event log handle + EVENTLOG_ERROR_TYPE, // event type + 0, // event category + // SVC_ERROR, + SERVICE_ERROR_NORMAL, // event identifier + NULL, // no security identifier + 2, // size of lpszStrings array + 0, // no binary data + lpszStrings, // array of strings + NULL); // no binary data + + DeregisterEventSource(hEventSource); + } + } + private: + models::ServiceInfo<> service_info; + + void initialize() + { + // service_info.service_name = L" Server Example"; + } + /** + class ServiceInfo; + + + service::ServiceEntryPoint::ServiceInfo service_info = {}; + + class ServiceInfo + { + public: + ServiceInfo() + { + } + + ServiceInfo(std::wstring &&name) : + service_name(const_cast(name.c_str())) + { + + } + + wchar_t *service_name; + wchar_t *service_description; + }; + */ + + }; +} + +#endif \ No newline at end of file diff --git a/ServiceExample/ServiceExample.vcxproj b/ServiceExample/ServiceExample.vcxproj new file mode 100644 index 0000000..2d4619d --- /dev/null +++ b/ServiceExample/ServiceExample.vcxproj @@ -0,0 +1,93 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {19AD11CD-7C72-41C6-B372-32A63C2EAB7A} + Win32Proj + ServiceExample + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + C:\Users\brahmix\Programming\c++\pre_2015\soci\soci_4_0_0\include;$(IncludePath) + C:\Users\brahmix\Programming\c++\pre_2015\soci\soci_4_0_0\bin;C:\Windows\System32;$(LibraryPath) + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + C:\Users\brahmix\Programming\c++\pre_2015\soci\soci_4_0_0\lib;%(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file