diff --git a/README.md b/README.md index cf39e7a..2d7fb47 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,10 @@ use service mode running dart to windows `service_base` from provides windows api => lib - - | - - v +> in `dart_windows_service_support` `WindowsServiceDLL` Import the api in lib and package the API => dll - | - - v - `dart_windows_service_support` use `dart:ffi` access dll api ## Example @@ -21,7 +14,7 @@ use service mode running dart to windows example global var ```dart -final dllPath = join(Directory.current.path, "../../../dll/WindowsServiceDLL.dll"); +final dllPath = join(Directory.current.path, "../../../dll/WindowsServiceDLL64.dll"); const serviceName = "dartTestService"; ``` @@ -44,9 +37,10 @@ void main(List args) { /// path servicePath.toNativeUtf16().cast(), - true, + 1, 1, Pointer.fromAddress(0), + 1 ); } ``` @@ -84,11 +78,7 @@ See `dart_windows_service_support/example` ## Make dll `WindowsServiceDLL.dll` -1. use VS2022 open `windows_platform\service_base` make project out `service-base.lib` file - -2. move `service-base.lib` to `windows_platform\WindowsServiceDLL\lib\service-base.lib` - -3. open project `windows_platform\WindowsServiceDLL` make out `WindowsServiceDLL.dll` +use VS2022 open project `windows_platform\WindowsServiceDLL` make out `WindowsServiceDLL.dll` > Complete the compilation of dll > diff --git a/dart_windows_service_support/CHANGELOG.md b/dart_windows_service_support/CHANGELOG.md index 89420ce..c4914a8 100644 --- a/dart_windows_service_support/CHANGELOG.md +++ b/dart_windows_service_support/CHANGELOG.md @@ -1,4 +1,10 @@ +# 0.0.3 + +feat: add delayed start option + +fix: use dart int to BOOL(int) + # 0.0.2 fix: export dartUninstallService from dll diff --git a/dart_windows_service_support/README.md b/dart_windows_service_support/README.md index 06b80ff..df46b3c 100644 --- a/dart_windows_service_support/README.md +++ b/dart_windows_service_support/README.md @@ -9,7 +9,7 @@ example global var ```dart -final dllPath = join(Directory.current.path, "../../../dll/WindowsServiceDLL.dll"); +final dllPath = join(Directory.current.path, "../../../dll/WindowsServiceDLL64.dll"); const serviceName = "dartTestService"; ``` @@ -32,9 +32,10 @@ void main(List args) { /// path servicePath.toNativeUtf16().cast(), - true, + 1, 1, Pointer.fromAddress(0), + 1 ); } ``` diff --git a/dart_windows_service_support/example/bin/install_service.dart b/dart_windows_service_support/example/bin/install_service.dart index daea5aa..cf723f5 100644 --- a/dart_windows_service_support/example/bin/install_service.dart +++ b/dart_windows_service_support/example/bin/install_service.dart @@ -23,8 +23,9 @@ void main(List args) { /// path servicePath.toNativeUtf16().cast(), - true, + 1, 1, Pointer.fromAddress(0), + 1, ); } diff --git a/dart_windows_service_support/example/lib/define.dart b/dart_windows_service_support/example/lib/define.dart index 598d0dc..b06c63d 100644 --- a/dart_windows_service_support/example/lib/define.dart +++ b/dart_windows_service_support/example/lib/define.dart @@ -2,5 +2,7 @@ import 'dart:io'; import 'package:path/path.dart'; -final dllPath = normalize(join(dirname(Platform.script.toFilePath()), "../../../dll/WindowsServiceDLL.dll")); -const serviceName = "dartTestService"; +/// WindowsServiceDLL64 is x64 +/// WindowsServiceDLL is x86 +final dllPath = normalize(join(dirname(Platform.script.toFilePath()), "../../../dll/WindowsServiceDLL64.dll")); +const serviceName = "dart_test_service"; diff --git a/dart_windows_service_support/lib/src/load_lib.dart b/dart_windows_service_support/lib/src/load_lib.dart index e73e829..d53a123 100644 --- a/dart_windows_service_support/lib/src/load_lib.dart +++ b/dart_windows_service_support/lib/src/load_lib.dart @@ -13,9 +13,10 @@ typedef CDartInstallService = ffi.Void Function( PCWSTR pszAccount, PCWSTR pszPassword, PCWSTR serviceCallPath, - ffi.Bool bRegisterWithEventLog, + ffi.Int bRegisterWithEventLog, DWORD dwNumMessageCategories, PCWSTR pszMessageResourceFilePath, + ffi.Int delayedStart, ); typedef DartInstallService = void Function( @@ -28,9 +29,10 @@ typedef DartInstallService = void Function( PCWSTR pszAccount, PCWSTR pszPassword, PCWSTR serviceCallPath, - bool bRegisterWithEventLog, + int bRegisterWithEventLog, int dwNumMessageCategories, PCWSTR pszMessageResourceFilePath, + int delayedStart, ); typedef CDartConnectService = ffi.Void Function(PCWSTR); diff --git a/dart_windows_service_support/pubspec.yaml b/dart_windows_service_support/pubspec.yaml index c793789..c3b7934 100644 --- a/dart_windows_service_support/pubspec.yaml +++ b/dart_windows_service_support/pubspec.yaml @@ -1,6 +1,6 @@ name: dart_windows_service_support description: Support running dart as a Windows service -version: 0.0.2 +version: 0.0.3 repository: https://github.com/au-top/dart_windows_service environment: diff --git a/windows_platform/.vs/ProjectSettings.json b/windows_platform/.vs/ProjectSettings.json deleted file mode 100644 index e257ff9..0000000 --- a/windows_platform/.vs/ProjectSettings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "CurrentProjectSetting": "无配置" -} \ No newline at end of file diff --git a/windows_platform/.vs/VSWorkspaceState.json b/windows_platform/.vs/VSWorkspaceState.json deleted file mode 100644 index 7c425e5..0000000 --- a/windows_platform/.vs/VSWorkspaceState.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ExpandedNodes": [ - "" - ], - "SelectedNode": "\\service-base.sln", - "PreviewInSolutionExplorer": false -} \ No newline at end of file diff --git a/windows_platform/.vs/slnx.sqlite b/windows_platform/.vs/slnx.sqlite deleted file mode 100644 index 35dacc7..0000000 Binary files a/windows_platform/.vs/slnx.sqlite and /dev/null differ diff --git a/windows_platform/.vs/windows_platform/FileContentIndex/ef202456-a62a-4d33-9697-0fed56b3ea79.vsidx b/windows_platform/.vs/windows_platform/FileContentIndex/ef202456-a62a-4d33-9697-0fed56b3ea79.vsidx deleted file mode 100644 index 27acda3..0000000 Binary files a/windows_platform/.vs/windows_platform/FileContentIndex/ef202456-a62a-4d33-9697-0fed56b3ea79.vsidx and /dev/null differ diff --git a/windows_platform/.vs/windows_platform/FileContentIndex/read.lock b/windows_platform/.vs/windows_platform/FileContentIndex/read.lock deleted file mode 100644 index e69de29..0000000 diff --git a/windows_platform/.vs/windows_platform/v17/.suo b/windows_platform/.vs/windows_platform/v17/.suo deleted file mode 100644 index 99e93a5..0000000 Binary files a/windows_platform/.vs/windows_platform/v17/.suo and /dev/null differ diff --git a/windows_platform/.vs/windows_platform/v17/Browse.VC.db b/windows_platform/.vs/windows_platform/v17/Browse.VC.db deleted file mode 100644 index c87f14e..0000000 Binary files a/windows_platform/.vs/windows_platform/v17/Browse.VC.db and /dev/null differ diff --git a/windows_platform/service_base/ServiceBase.cpp b/windows_platform/WindowsServiceDLL/ServiceBase.cpp similarity index 99% rename from windows_platform/service_base/ServiceBase.cpp rename to windows_platform/WindowsServiceDLL/ServiceBase.cpp index 81f93db..d77da66 100644 --- a/windows_platform/service_base/ServiceBase.cpp +++ b/windows_platform/WindowsServiceDLL/ServiceBase.cpp @@ -17,15 +17,10 @@ * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ -#pragma region Includes -#include -#include - +#include "pch.h" #include "ServiceBase.h" -#pragma endregion -#pragma region Static Members // Initialize the singleton service instance. CServiceBase *CServiceBase::s_service = NULL; @@ -628,4 +623,3 @@ void CServiceBase::WriteErrorLogEntry(PCWSTR pszFunction, DWORD dwError) WriteLogEntry(szMessage, EVENTLOG_ERROR_TYPE, m_dwErrorEventId, m_wErrorCategoryId); } -#pragma endregion \ No newline at end of file diff --git a/windows_platform/WindowsServiceDLL/includes/ServiceBase.h b/windows_platform/WindowsServiceDLL/ServiceBase.h similarity index 100% rename from windows_platform/WindowsServiceDLL/includes/ServiceBase.h rename to windows_platform/WindowsServiceDLL/ServiceBase.h diff --git a/windows_platform/service_base/ServiceInstaller.cpp b/windows_platform/WindowsServiceDLL/ServiceInstaller.cpp similarity index 96% rename from windows_platform/service_base/ServiceInstaller.cpp rename to windows_platform/WindowsServiceDLL/ServiceInstaller.cpp index 573e387..a326c08 100644 --- a/windows_platform/service_base/ServiceInstaller.cpp +++ b/windows_platform/WindowsServiceDLL/ServiceInstaller.cpp @@ -15,9 +15,8 @@ * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. \***************************************************************************/ -#pragma region "Includes" #include "ServiceInstaller.h" -#pragma endregion +#include "pch.h" // // FUNCTION: InstallService @@ -52,7 +51,8 @@ void InstallService(PCWSTR pszServiceName, PCWSTR serviceCallPath, BOOL bRegisterWithEventLog, DWORD dwNumMessageCategories, - PCWSTR pszMessageResourceFilePath + PCWSTR pszMessageResourceFilePath, + BOOL delayedStart ) { wchar_t wszPath[MAX_PATH]; @@ -95,6 +95,7 @@ void InstallService(PCWSTR pszServiceName, { // Add service description SERVICE_DESCRIPTION sd; + wchar_t wszDesc[1024]; wcsncpy_s(wszDesc, _countof(wszDesc), pszDescription, _TRUNCATE); @@ -107,6 +108,16 @@ void InstallService(PCWSTR pszServiceName, goto Cleanup; } + if (delayedStart) { + SERVICE_DELAYED_AUTO_START_INFO sdasi = { delayedStart }; + if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &sdasi)) + { + wprintf(L"Couldn't set service delayed auto start with error code: 0x%08lx\n", GetLastError()); + goto Cleanup; + } + + } + // Register service with event logger (optional) if (bRegisterWithEventLog) { diff --git a/windows_platform/service_base/ServiceInstaller.h b/windows_platform/WindowsServiceDLL/ServiceInstaller.h similarity index 96% rename from windows_platform/service_base/ServiceInstaller.h rename to windows_platform/WindowsServiceDLL/ServiceInstaller.h index 66d40b5..41a13e9 100644 --- a/windows_platform/service_base/ServiceInstaller.h +++ b/windows_platform/WindowsServiceDLL/ServiceInstaller.h @@ -59,7 +59,8 @@ void InstallService(PCWSTR pszServiceName, PCWSTR serviceCallPath, BOOL bRegisterWithEventLog = TRUE, DWORD dwNumMessageCategories = 0, - PCWSTR pszMessageResourceFilePath = NULL + PCWSTR pszMessageResourceFilePath = NULL, + BOOL delayedStart = FALSE ); // diff --git a/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj b/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj index 3b6d37a..61a34d8 100644 --- a/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj +++ b/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj @@ -99,7 +99,7 @@ true Use pch.h - ;$(SolutionDir)includes\ + %(AdditionalIncludeDirectories) MultiThreaded @@ -109,7 +109,8 @@ true false %(AdditionalDependencies) - $(ProjectDir)lib; + + @@ -141,7 +142,7 @@ true Use pch.h - $(ProjectDir)includes;%(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) MultiThreaded @@ -150,7 +151,8 @@ true true false - $(ProjectDir)lib;C:\Users\autop\source\repos\WindowsServiceDLL\lib + + %(AdditionalDependencies) @@ -159,6 +161,8 @@ + + @@ -169,6 +173,8 @@ Create Create + + diff --git a/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj.filters b/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj.filters index 18ac136..fc9e4e1 100644 --- a/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj.filters +++ b/windows_platform/WindowsServiceDLL/WindowsServiceDLL.vcxproj.filters @@ -27,6 +27,12 @@ 头文件 + + 头文件 + + + 头文件 + @@ -38,5 +44,11 @@ 源文件 + + 源文件 + + + 源文件 + \ No newline at end of file diff --git a/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.cpp b/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.cpp index 7f4319e..f624568 100644 --- a/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.cpp +++ b/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.cpp @@ -15,7 +15,8 @@ extern "C" void DartInstallService(PCWSTR pszServiceName, PCWSTR serviceCallPath, BOOL bRegisterWithEventLog, DWORD dwNumMessageCategories, - PCWSTR pszMessageResourceFilePath + PCWSTR pszMessageResourceFilePath, + BOOL delayedStart ) { InstallService(pszServiceName, @@ -29,7 +30,8 @@ extern "C" void DartInstallService(PCWSTR pszServiceName, serviceCallPath, bRegisterWithEventLog, dwNumMessageCategories, - pszMessageResourceFilePath + pszMessageResourceFilePath, + delayedStart ); } diff --git a/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.h b/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.h index fe33c3c..bb13ed4 100644 --- a/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.h +++ b/windows_platform/WindowsServiceDLL/exportWindowsServiceDLLApi.h @@ -14,7 +14,8 @@ extern "C" __declspec(dllexport) void DartInstallService(PCWSTR pszServiceName, PCWSTR serviceCallPath, BOOL bRegisterWithEventLog, DWORD dwNumMessageCategories, - PCWSTR pszMessageResourceFilePath + PCWSTR pszMessageResourceFilePath, + BOOL delayedStart ); extern "C" __declspec(dllexport) void DartConnectService( diff --git a/windows_platform/WindowsServiceDLL/includes/ServiceInstaller.h b/windows_platform/WindowsServiceDLL/includes/ServiceInstaller.h deleted file mode 100644 index be243d4..0000000 --- a/windows_platform/WindowsServiceDLL/includes/ServiceInstaller.h +++ /dev/null @@ -1,76 +0,0 @@ -/****************************** Module Header ******************************\ -* Module Name: ServiceInstaller.h -* Project: service-base -* Copyright (c) Microsoft Corporation. -* Copyright (c) Tromgy (tromgy@yahoo.com) -* -* The file declares functions that install and uninstall the service. -* -* This source is subject to the Microsoft Public License. -* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL. -* All other rights reserved. -* -* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -\***************************************************************************/ - -#pragma once - -#include -#include - -// -// FUNCTION: InstallService -// -// PURPOSE: Install the current application as a service to the local -// service control manager database. -// -// PARAMETERS: -// * pszServiceName - the name of the service to be installed -// * pszDisplayName - the display name of the service -// * dwStartType - the service start option. This parameter can be one of -// the following values: SERVICE_AUTO_START, SERVICE_BOOT_START, -// SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START. -// * pszDependencies - a pointer to a double null-terminated array of null- -// separated names of services or load ordering groups that the system -// must start before this service. -// * pszAccount - the name of the account under which the service runs. -// * pszPassword - the password to the account name. -// * bRegisterWithEventLog - set this to TRUE if the service is intended to -// write log messages into Windows Application log (default). -// * dwNumMessageCategories - number of message categories that will be logged. -// * pszMessageResourceFilePath - the full path to a file containing message -// string resources to be displayed for event ids and message categories. -// if NULL and bRegisterWithEventLog is TRUE, it expected that -// the main service executable contains the message string resources. -// -// NOTE: If the function fails to install the service, it prints the error -// in the standard output stream for users to diagnose the problem. -// -void InstallService(PCWSTR pszServiceName, - PCWSTR pszDisplayName, - PCWSTR pszDescription, - PCWSTR pszParams, - DWORD dwStartType, - PCWSTR pszDependencies, - PCWSTR pszAccount, - PCWSTR pszPassword, - PCWSTR serviceCallPath, - BOOL bRegisterWithEventLog = TRUE, - DWORD dwNumMessageCategories = 0, - PCWSTR pszMessageResourceFilePath = NULL -); -// -// FUNCTION: UninstallService -// -// PURPOSE: Stop and remove the service from the local service control -// manager database. -// -// PARAMETERS: -// * pszServiceName - the name of the service to be removed. -// -// NOTE: If the function fails to uninstall the service, it prints the -// error in the standard output stream for users to diagnose the problem. -// -void UninstallService(PCWSTR pszServiceName); \ No newline at end of file diff --git a/windows_platform/WindowsServiceDLL/pch.h b/windows_platform/WindowsServiceDLL/pch.h index a7a22e6..9ed91fd 100644 --- a/windows_platform/WindowsServiceDLL/pch.h +++ b/windows_platform/WindowsServiceDLL/pch.h @@ -11,11 +11,7 @@ #include "framework.h" #include -#ifdef _WIN64 -#pragma comment(lib, "service-base-64.lib") -#else -#pragma comment(lib, "service-base.lib") -#endif // WIN64 - - +#include +#include +#include #endif //PCH_H diff --git a/windows_platform/service_base/.gitignore b/windows_platform/service_base/.gitignore deleted file mode 100644 index 54725a1..0000000 --- a/windows_platform/service_base/.gitignore +++ /dev/null @@ -1,51 +0,0 @@ -# Prerequisites -*.d - -# Build folders -[Rr]elease/ -[Dd]ebug/ - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app -*.user - -# Other build artifacts -*.vs -*.bin -*.res -*.log -*.pdb -*.tlog -*.idb -*.ilk -*.iobj -*.ipdb -event_ids.rc -event_ids.h diff --git a/windows_platform/service_base/LICENSE b/windows_platform/service_base/LICENSE deleted file mode 100644 index 203e8e1..0000000 --- a/windows_platform/service_base/LICENSE +++ /dev/null @@ -1,39 +0,0 @@ -License - -MICROSOFT LIMITED PUBLIC LICENSE version 1.1 -This license governs use of code in this github repository. If you use such code (the “software”), you accept this license. If you do not accept the license, do not use the software. - - -1. Definitions - -The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have the same meaning here as under U.S. copyright law. - -A “contribution” is the original software, or any additions or changes to the software. - -A “contributor” is any person that distributes its contribution under this license. - -“Licensed patents” are a contributor’s patent claims that read directly on its contribution. - - -2. Grant of Rights - -(A) Copyright Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. - -(B) Patent Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. - - -3. Conditions and Limitations - -(A) No Trademark License- This license does not grant you rights to use any contributors’ name, logo, or trademarks. - -(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. - -(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. - -(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. - -(E) The software is licensed “as-is.” You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. - -(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) extend only to the software or derivative works that you create that run directly on a Microsoft Windows operating system product, Microsoft run-time technology (such as the .NET Framework or Silverlight), or Microsoft application platform (such as Microsoft Office or Microsoft Dynamics). - - diff --git a/windows_platform/service_base/README.md b/windows_platform/service_base/README.md deleted file mode 100644 index e1a3511..0000000 --- a/windows_platform/service_base/README.md +++ /dev/null @@ -1,156 +0,0 @@ -[![Build status](https://ci.appveyor.com/api/projects/status/k197mtn89ylpjyp7?svg=true)](https://ci.appveyor.com/project/tromgy/service-base) - -# C++ class and library to implement a Windows service - -This project provides a C++ base class with minimal dependencies that you can derive from to create a Microsoft Windows service executable. - -It also includes a complete service example that utilizes this class. - -## Background - -Years ago (circa 2008?) Microsoft published the original C++ class and a sample service project that was once available at - -https://code.msdn.microsoft.com/windowsapps/CppWindowsService-cacf4948 - -This project is an attempt to improve on that original example in the areas of security, usability, and convenience, as well as trying to cross the "t"s and dot the "i"s. - -## Improvements - -- The `InstallService` function in **ServiceInstaller.cpp** encloses the service executable path in quotes to avoid a common security vulnerability (https://www.commonexploits.com/unquoted-service-paths/) - -- The same function also allows to set the command line parameters to the service executable when it runs as a service. - -- The service installation includes the service description argument, which the original installer was lacking. - -- The `CServiceBase` class now provides support for logging into Windows Event Log the _proper_ way, with event and category ids. You will no longer see "Either the component that raises this event is not installed on your local computer or the installation is corrupted." in the Event Viewer. - -- You can also override the logging function to log into your own log file instead of Windows Event Log. - -## Creating the service - -The project includes a sample service in the **sample-service** subdirectory. - -To create the service follow these steps: - -1. Set up a Visual C++ project statically linking with **service-base.lib** -2. Derive a class from `CServiceBase` like this -``` - class CSampleService: public CServiceBase -``` -Override (implement with your service-specific details) virtual methods: -- `OnStart` -- `OnStop` -- `OnPause` (sample service does not implement this one) - -Create a static method where the actual service work will be performed (on a separate thread). In sample service it is done -in `static DWORD __stdcall ServiceRunner(void* self)`. - -This static method takes a pointer to the service instance in the `self` argument. - -In addition our sample service provides an option to run it as a regular (non-service) process by providing a command line argument called **run** (while to run as a service it takes the **serve** argument). - -## Command line - -The sample service demonstrates how to implement a rich command line interface. - -Command line parameters are used for installing/uninstalling the service as well as at the service run time. The original Microsoft example did not have an ability to install the service with command line parameters to be used at run time. - -In our case the service "uses" a configuration file at run time, so when installing the service we can use the following command: -``` - c:\github\service-base\sample-service\Release>sample-service install -config c:\Users\Me\my-config.cfg -``` -This will install the service to run as: - -**"c:\github\service-base\sample-service\Release\sample-service.exe" serve -config "c:\Users\Me\my-config.cfg"** - -It should be noted that these command line parameters are _not_ getting passed to the service in the `OnStart` method, contrary to the method signature. Instead, we have to store number of arguments and their array (`m_argc` and `m_argv`) with the class instance, and use them from the same `OnStart` method. - -These class members are set by calling `service.SetCommandLine(argc, argv)` method from the `wmain` function. - -## Logging - -Sample service also demonstrates correct way of logging information into the Windows Event Log. The `CServiceBase::WriteLogEntry` method takes the following parameters: - -- `pszMessage`: the message(s) to be displayed on the **Details** page of the logged event when viewed with Windows Event Viewer. If you wish to display multi-line message, just separate lines with `\n` in this string. -- `wType`: type of the message (information, warning, error, etc.) -- these are defined in system SDK's **winnt.h** file. -- `dwEventId`: numerical event id matching the string to be displayed on the **General** page in Event Viewer. These strings should come from resources in your service executable or a separate resource DLL (more details below). -- `wCategory`: numerical category id matching the string to be displayed in the **Task Category** column in Event Viewer. - -The last two arguments are optional, but lacking event id the logged event would look ugly in the Event Viewer with the following text appearing on the **General** page: - - The description for Event ID 0 from source cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer. - -To allow the same logging options from _within_ the `CServiceBase` class, the constructor was extended to take two optional arguments: `dwErrorEventId` and `wErrorCategoryId`. It is expected (if these arguments are specified when creating the service instance) that strings matching these ids can be found in the resources. These strings will be used only for error reporting (the base class only writes logging messages if something goes wrong). - -To provide strings for event and category ids we need to have a two-step process for building the string resources: - -1. Run _message compiler_ (**mc.exe**) on the message strings (.mc) file. That generates resources (.rc) file, corresponding header file to be included in your code, and the binary (.bin) file containing the actual strings for the events and categories. - -2. Run resource compiler to generate .res file. - -The resulting .res file is then linked with your executable as any other resource file. - -Each message string entry in the .mc file has the following format (this is not a complete description): - -``` -MessageId=10 -SymbolicName=MSG_STARTUP -Severity=Informational -Facility=Application -Language=English -Startup -. -``` -The `MessageId` then becomes event or category id to be passed as its `SymbolicName` to the `WriteEventLog` method. It will be defined as -``` -#define MSG_STARTUP ((DWORD)0x4000000AL) -``` -in the generated header file. - -The `Language` value comes from the language defintion in the same message file: - -``` -LanguageNames=(EnglishUS=0x409:MSG00409) -``` - -Language ids can be found at https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-input-locales-for-windows-language-packs - -so for instance to implement message strings also in Faroese you could use: -``` -LanguageNames=( -EnglishUS=0x409:MSG00409 -Faroese=0438:MSG00406 -) -``` -and then refer to that language in your message entry. - -The actual text that will be displayed on the **General** page goes after the `Language` line and before the line containing the period (`.`), which is in the example above would be **Startup**. - -Category names can be created similarly: - -``` -MessageId=1 -SymbolicName=CATEGORY_SERVICE -Language=EnglishUS -Service -. -``` - -Our sample service contains only one category, called **Service**. - -Once we have the resources in the main executable or a separate resource DLL, these need to be registered when the service is installed. The `InstallService` function takes care of that. The last three (optional) arguments are: - -- `bRegisterWithEventLog`: pass `TRUE` to create Registry entries so that Event Viewer can display your log messages properly. -- `dwNumMessageCategories`: number of message categores (which were described above). -- `pszMessageResourceFilePath`: full path to the file containing message string resources. If this parameter is `NULL`, and -`bRegisterWithEventLog` is `TRUE`, the service executable path is used. So you only need to supply this parameter if you have you message strings in a separate resource DLL. - -The registration information is stored in the following key: - -**HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\sample-service** - -Finally, if you do not wish to utilize Windows Event Log system, you can completely override `CServiceBase::WriteLogEntry` method to log into your own file for example. - -## Building - -The **master** branch now contains the solutions and projects for MS Visual Studio 2022. The **VS2019** and **VS2017** branches contain the same for MS Visual Studio 2019 and MS Visual Studio 2017 accordingly. diff --git a/windows_platform/service_base/ServiceBase.h b/windows_platform/service_base/ServiceBase.h deleted file mode 100644 index bec59f6..0000000 --- a/windows_platform/service_base/ServiceBase.h +++ /dev/null @@ -1,137 +0,0 @@ -/****************************** Module Header ******************************\ -* Module Name: ServiceBase.h -* Project: service-base -* Copyright (c) Microsoft Corporation. -* Copyright (c) Tromgy (tromgy@yahoo.com) -* -* Provides a base class for a service that will exist as part of a service -* application. CServiceBase must be derived from when creating a new service -* class. -* -* This source is subject to the Microsoft Public License. -* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL. -* All other rights reserved. -* -* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -\***************************************************************************/ - -#pragma once - -#include - -class CServiceBase -{ - public: - - // Register the executable for a service with the Service Control Manager - // (SCM). After you call Run(ServiceBase), the SCM issues a Start command, - // which results in a call to the OnStart method in the service. This - // method blocks until the service has stopped. - static BOOL Run(CServiceBase &service); - - // Service object constructor. The optional parameters (fCanStop, - // fCanShutdown and fCanPauseContinue) allow you to specify whether the - // service can be stopped, paused and continued, or be notified when - // system shutdown occurs. - CServiceBase(PCWSTR pszServiceName, - BOOL fCanStop = TRUE, - BOOL fCanShutdown = TRUE, - BOOL fCanPauseContinue = FALSE, - DWORD dwErrorEventId = 0, - WORD wErrorCategoryId = 0); - - // Service object destructor. - virtual ~CServiceBase(void); - - // A command line to be passed to the service when it runs - void SetCommandLine(int argc, PWSTR argv[]) - { - m_argc = argc; - m_argv = argv; - } - - // Stop the service. - void Stop(); - - protected: - - // When implemented in a derived class, executes when a Start command is - // sent to the service by the SCM or when the operating system starts - // (for a service that starts automatically). Specifies actions to take - // when the service starts. - virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv); - - // When implemented in a derived class, executes when a Stop command is - // sent to the service by the SCM. Specifies actions to take when a - // service stops running. - virtual void OnStop(); - - // When implemented in a derived class, executes when a Pause command is - // sent to the service by the SCM. Specifies actions to take when a - // service pauses. - virtual void OnPause(); - - // When implemented in a derived class, OnContinue runs when a Continue - // command is sent to the service by the SCM. Specifies actions to take - // when a service resumes normal functioning after being paused. - virtual void OnContinue(); - - // When implemented in a derived class, executes when the system is - // shutting down. Specifies what should occur immediately prior to the - // system shutting down. - virtual void OnShutdown(); - - // Set the service status and report the status to the SCM. - void SetServiceStatus(DWORD dwCurrentState, - DWORD dwWin32ExitCode = NO_ERROR, - DWORD dwWaitHint = 0); - - // Log a message to the Application event log. - virtual void WriteLogEntry(PCWSTR pszMessage, WORD wType, DWORD dwEventId = 0, WORD wCategory = 0); - - // Log an error message to the Application event log. - virtual void WriteErrorLogEntry(PCWSTR pszFunction, - DWORD dwError = GetLastError()); - - // Entry point for the service. It registers the handler function for the - // service and starts the service. - static void WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv); - - // The function is called by the SCM whenever a control code is sent to - // the service. - static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); - - // Start the service. - void Start(DWORD dwArgc, PWSTR *pszArgv); - - // Pause the service. - void Pause(); - - // Resume the service after being paused. - void Continue(); - - // Execute when the system is shutting down. - void Shutdown(); - - // The singleton service instance. - static CServiceBase *s_service; - - // The name of the service - PCWSTR m_name; - - // Command line for the service - int m_argc; - PWSTR* m_argv; - - // The status of the service - SERVICE_STATUS m_status; - - // The service status handle - SERVICE_STATUS_HANDLE m_statusHandle; - - // This is used for error logging into Windows Event Log - DWORD m_dwErrorEventId; - WORD m_wErrorCategoryId; -}; \ No newline at end of file diff --git a/windows_platform/service_base/appveyor.yml b/windows_platform/service_base/appveyor.yml deleted file mode 100644 index 4a96f96..0000000 --- a/windows_platform/service_base/appveyor.yml +++ /dev/null @@ -1,5 +0,0 @@ -version: 1.0.{build} -image: Visual Studio 2022 -build: - project: service-base.sln - verbosity: minimal diff --git a/windows_platform/service_base/service-base.sln b/windows_platform/service_base/service-base.sln deleted file mode 100644 index 693f8e0..0000000 --- a/windows_platform/service_base/service-base.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31815.197 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "service-base", "service-base.vcxproj", "{8D315DE1-90D2-47EF-9652-95FBDB6DB26F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Debug|x64.ActiveCfg = Debug|x64 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Debug|x64.Build.0 = Debug|x64 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Debug|x86.ActiveCfg = Debug|Win32 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Debug|x86.Build.0 = Debug|Win32 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Release|x64.ActiveCfg = Release|x64 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Release|x64.Build.0 = Release|x64 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Release|x86.ActiveCfg = Release|Win32 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D98DF2C4-8E34-475E-8656-6066BE5115C4} - EndGlobalSection -EndGlobal diff --git a/windows_platform/service_base/service-base.vcxproj b/windows_platform/service_base/service-base.vcxproj deleted file mode 100644 index 43c38b7..0000000 --- a/windows_platform/service_base/service-base.vcxproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8D315DE1-90D2-47EF-9652-95FBDB6DB26F} - Win32Proj - servicebase - 10.0 - - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - StaticLibrary - true - v143 - Unicode - - - StaticLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - true - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - Async - MultiThreaded - - - Windows - true - - - - - Use - Level3 - Disabled - true - _DEBUG;_LIB;%(PreprocessorDefinitions) - true - Async - MultiThreaded - - - Windows - true - - - - - Use - Level3 - MaxSpeed - true - true - true - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - Async - MultiThreaded - - - Windows - true - true - true - - - - - Use - Level3 - MaxSpeed - true - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - true - Async - MultiThreaded - - - Windows - true - true - true - - - - - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - NotUsing - - - - - - - - - - \ No newline at end of file diff --git a/windows_platform/service_base/service-base.vcxproj.filters b/windows_platform/service_base/service-base.vcxproj.filters deleted file mode 100644 index ab834de..0000000 --- a/windows_platform/service_base/service-base.vcxproj.filters +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - \ No newline at end of file