├── bin ├── sFany.exe └── sFany.ini ├── sFany ├── sFany.cpp ├── stdafx.cpp ├── stdafx.h ├── targetver.h ├── utils.h ├── Service.h ├── sFany.sln ├── sFany.vcxproj.filters ├── utils.cpp ├── sFany.vcxproj └── Service.cpp ├── .github └── workflows │ └── msbuild.yml ├── README.md └── .gitignore /bin/sFany.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stxh/sFany/HEAD/bin/sFany.exe -------------------------------------------------------------------------------- /sFany/sFany.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stxh/sFany/HEAD/sFany/sFany.cpp -------------------------------------------------------------------------------- /sFany/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stxh/sFany/HEAD/sFany/stdafx.cpp -------------------------------------------------------------------------------- /sFany/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stxh/sFany/HEAD/sFany/stdafx.h -------------------------------------------------------------------------------- /sFany/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stxh/sFany/HEAD/sFany/targetver.h -------------------------------------------------------------------------------- /bin/sFany.ini: -------------------------------------------------------------------------------- 1 | [Service] 2 | Name=sFany 3 | server1 = e:\MyServer\nginx\nginx.exe -p e:\MyServer\nginx -c E:\MyWeb\conf\nginx.conf 4 | server2 = e:\MyServer\php\php-cgi.exe -b 127.0.0.1:9000 -c E:\MyWeb\conf\php32.ini -------------------------------------------------------------------------------- /sFany/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.h 3 | */ 4 | #pragma once 5 | #include 6 | #include 7 | 8 | typedef enum _DEBUG_OUTPUT_TYPE { 9 | E_DEBUG_NULL, 10 | E_DEBUG_STRING, 11 | E_DEBUG_LOG, 12 | E_DEBUG_ALL, 13 | } DEBUG_OUTPUT_TYPE; 14 | 15 | int SetDebugOutputType(DEBUG_OUTPUT_TYPE dotOption); 16 | 17 | BOOL isAdmin(); 18 | 19 | BOOL WriteLog(TCHAR* pLogFormat,...); 20 | 21 | BOOL WriteLogA(CHAR* pLogFormat,...); 22 | -------------------------------------------------------------------------------- /sFany/Service.h: -------------------------------------------------------------------------------- 1 | // Service.cpp : Defines the entry point for the console application. 2 | // 3 | #pragma once 4 | #include 5 | #include "utils.h" 6 | 7 | /** Window Service Functions**/ 8 | DWORD Install(const TCHAR* pPath, const TCHAR* pName); 9 | VOID UnInstall(const TCHAR* pName); 10 | BOOL KillService(const TCHAR* pName); 11 | BOOL RunService(const TCHAR* pName); 12 | DWORD QueryService(const TCHAR* pName); 13 | VOID ExecuteService(const TCHAR* pName,LPSERVICE_MAIN_FUNCTION UserServiceMain); 14 | 15 | VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv); 16 | VOID WINAPI ServiceHandler(DWORD fdwControl); 17 | 18 | typedef VOID (WINAPI *LPSERVICE_USER_FUNCTION)(DWORD fdwControl); -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: sFany 2 | 3 | on: 4 | push: 5 | branches: dev 6 | pull_request: 7 | branches: master 8 | 9 | env: 10 | # Path to the solution file relative to the root of the project. 11 | SOLUTION_FILE_PATH: . 12 | 13 | # Configuration type to build. 14 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 15 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 16 | BUILD_CONFIGURATION: Release 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | build: 23 | runs-on: windows-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Add MSBuild to PATH 29 | uses: microsoft/setup-msbuild@v1.0.2 30 | 31 | - name: Restore NuGet packages 32 | working-directory: ${{env.GITHUB_WORKSPACE}} 33 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 34 | 35 | - name: Build 36 | working-directory: ${{env.GITHUB_WORKSPACE}} 37 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 38 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 39 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 40 | -------------------------------------------------------------------------------- /sFany/sFany.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30804.86 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sFany", "sFany.vcxproj", "{D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Debug|Win32.Build.0 = Debug|Win32 18 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Debug|x64.ActiveCfg = Release|x64 19 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Debug|x64.Build.0 = Release|x64 20 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Release|Win32.ActiveCfg = Release|x64 21 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Release|Win32.Build.0 = Release|x64 22 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Release|x64.ActiveCfg = Release|x64 23 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {CDC969EB-4456-4322-98F4-E4AF736863CD} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /sFany/sFany.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Heads 20 | 21 | 22 | Heads 23 | 24 | 25 | Heads 26 | 27 | 28 | Heads 29 | 30 | 31 | 32 | 33 | Sources 34 | 35 | 36 | Sources 37 | 38 | 39 | Sources 40 | 41 | 42 | Sources 43 | 44 | 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sFany 2 | ===== 3 | 4 | Recently I want to start nginx server as a windows service. But it is not windows service itself. 5 | Some solutions use srvany.exe from Microsoft. Yes it works. But if you want start PHP as server as 6 | same time, srvany can't do it. 7 | 8 | So I write my srvany, it is sFany here. 9 | 10 | Usage 11 | ===== 12 | sFany [option] 13 | 14 | Options: 15 | -v View services list 16 | -i Install service 17 | -u Uninstall service 18 | -k Kill/stop service 19 | -s Start service 20 | 21 | Setting 22 | ======= 23 | sFany use ini configuaration file like this: 24 | 25 | [Service] 26 | Name=sFany 27 | server1 = path_to\server1.exe -c command line 28 | server2 = path_to\server2.exe -c command line 29 | ...... 30 | 31 | Contact 32 | ======= 33 | Write an email to stxh007@gmail.com 34 | 35 | License 36 | ======= 37 | (The MIT License) 38 | 39 | Copyright (c) 2012 stxh007@gmail.com 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Virtual C/C++ ignore file # 2 | ############################# 3 | # User-specific files 4 | *.suo 5 | *.user 6 | *.sln.docstates 7 | .vs/ 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | *.pubxml 98 | 99 | # NuGet Packages Directory 100 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 101 | #packages/ 102 | 103 | # Windows Azure Build Output 104 | csx 105 | *.build.csdef 106 | 107 | # Windows Store app package directory 108 | AppPackages/ 109 | 110 | # Others 111 | sql/ 112 | *.Cache 113 | ClientBin/ 114 | [Ss]tyle[Cc]op.* 115 | ~$* 116 | *~ 117 | *.dbmdl 118 | *.[Pp]ublish.xml 119 | *.pfx 120 | *.publishsettings 121 | 122 | # RIA/Silverlight projects 123 | Generated_Code/ 124 | 125 | # Backup & report files from converting an old project file to a newer 126 | # Visual Studio version. Backup files are not needed, because we have git ;-) 127 | _UpgradeReport_Files/ 128 | Backup*/ 129 | UpgradeLog*.XML 130 | UpgradeLog*.htm 131 | 132 | # SQL Server files 133 | App_Data/*.mdf 134 | App_Data/*.ldf 135 | 136 | # ========================= 137 | # Windows detritus 138 | # ========================= 139 | 140 | # Windows image file caches 141 | Thumbs.db 142 | ehthumbs.db 143 | 144 | # Folder config file 145 | Desktop.ini 146 | 147 | # Recycle Bin used on file shares 148 | $RECYCLE.BIN/ 149 | 150 | # Mac crap 151 | .DS_Store -------------------------------------------------------------------------------- /sFany/utils.cpp: -------------------------------------------------------------------------------- 1 | /*********************************** 2 | * utils 3 | * 4 | ***********************************/ 5 | #include "utils.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static const int MAX_BUFFER_LEN = 1024; 12 | 13 | DEBUG_OUTPUT_TYPE g_dotDebugOption=E_DEBUG_NULL; 14 | //DEBUG_OUTPUT_TYPE g_dotDebugOption = E_DEBUG_LOG; 15 | 16 | int SetDebugOutputType(DEBUG_OUTPUT_TYPE dotOption) { 17 | return g_dotDebugOption=dotOption; 18 | } 19 | 20 | BOOL WriteLog(TCHAR* pLogFormat,...) { 21 | 22 | TCHAR strMessage[MAX_BUFFER_LEN]; 23 | 24 | if (g_dotDebugOption > E_DEBUG_NULL) { 25 | TCHAR strMsg[MAX_BUFFER_LEN]; 26 | va_list argptr; 27 | va_start ( argptr, pLogFormat ); 28 | _vsntprintf(strMsg,MAX_BUFFER_LEN,pLogFormat,argptr); 29 | 30 | SYSTEMTIME oT; 31 | ::GetLocalTime(&oT); 32 | 33 | _stprintf(strMessage,__T("%02d-%02d %02d:%02d:%02d %s"),oT.wMonth,oT.wDay,oT.wHour,oT.wMinute,oT.wSecond,strMsg); 34 | } 35 | 36 | if (g_dotDebugOption == E_DEBUG_LOG || g_dotDebugOption == E_DEBUG_ALL) { // WRITE_DEBUG_LOG 37 | TCHAR strModuleFile[MAX_BUFFER_LEN]; 38 | DWORD dwSize = GetModuleFileName(NULL, strModuleFile, MAX_BUFFER_LEN); 39 | 40 | #ifdef _UNICODE 41 | std::wstring strLogFile(strModuleFile); 42 | std::wfstream of; 43 | #else 44 | std::string strLogFile(strModuleFile); 45 | std::fstream of; 46 | #endif 47 | 48 | strLogFile += __T(".log"); 49 | of.open(strLogFile,std::ios::app); 50 | of << strMessage << std::endl; 51 | } 52 | 53 | if (g_dotDebugOption == E_DEBUG_STRING || g_dotDebugOption == E_DEBUG_ALL) { //WRITE_DEBUG 54 | OutputDebugString(strMessage); 55 | } 56 | 57 | return TRUE; 58 | } 59 | 60 | BOOL WriteLogA(CHAR* pLogFormat,...) { 61 | 62 | CHAR strMessage[MAX_BUFFER_LEN]; 63 | 64 | if (g_dotDebugOption > E_DEBUG_NULL) { 65 | CHAR strMsg[MAX_BUFFER_LEN]; 66 | va_list argptr; 67 | va_start ( argptr, pLogFormat ); 68 | _vsnprintf(strMsg,MAX_BUFFER_LEN,pLogFormat,argptr); 69 | 70 | SYSTEMTIME oT; 71 | ::GetLocalTime(&oT); 72 | 73 | sprintf(strMessage,"%02d-%02d %02d:%02d:%02d %s",oT.wMonth,oT.wDay,oT.wHour,oT.wMinute,oT.wSecond,strMsg); 74 | } 75 | 76 | if (g_dotDebugOption == E_DEBUG_LOG || g_dotDebugOption == E_DEBUG_ALL) { // WRITE_DEBUG_LOG 77 | TCHAR strModuleFile[MAX_BUFFER_LEN]; 78 | DWORD dwSize = GetModuleFileName(NULL, strModuleFile, MAX_BUFFER_LEN); 79 | 80 | #ifdef _UNICODE 81 | std::wstring strLogFile(strModuleFile); 82 | std::wfstream of; 83 | #else 84 | std::string strLogFile(strModuleFile); 85 | std::fstream of; 86 | #endif 87 | 88 | strLogFile += __T(".log"); 89 | of.open(strLogFile,std::ios::app); 90 | of << strMessage << std::endl; 91 | } 92 | 93 | if (g_dotDebugOption == E_DEBUG_STRING || g_dotDebugOption == E_DEBUG_ALL) { //WRITE_DEBUG 94 | std::string strTmp(strMessage); 95 | std::wstring wstrMessage(strTmp.begin(),strTmp.end()); 96 | OutputDebugString(wstrMessage.c_str()); 97 | } 98 | 99 | return TRUE; 100 | } 101 | 102 | BOOL isAdmin() { 103 | SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; 104 | PSID AdministratorsGroup; 105 | // Initialize SID. 106 | if( !AllocateAndInitializeSid( &NtAuthority, 107 | 2, 108 | SECURITY_BUILTIN_DOMAIN_RID, 109 | DOMAIN_ALIAS_RID_ADMINS, 110 | 0, 0, 0, 0, 0, 0, 111 | &AdministratorsGroup)) 112 | { 113 | // Initializing SID Failed. 114 | return false; 115 | } 116 | // Check whether the token is present in admin group. 117 | BOOL IsInAdminGroup = FALSE; 118 | if( !CheckTokenMembership( NULL, 119 | AdministratorsGroup, 120 | &IsInAdminGroup )) 121 | { 122 | // Error occurred. 123 | IsInAdminGroup = FALSE; 124 | } 125 | // Free SID and return. 126 | FreeSid(AdministratorsGroup); 127 | return IsInAdminGroup; 128 | } -------------------------------------------------------------------------------- /sFany/sFany.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {D6A8A888-5FE5-477E-B7AD-4DA23BDEA046} 23 | Win32Proj 24 | sFany 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | Unicode 32 | v142 33 | false 34 | false 35 | 36 | 37 | Application 38 | true 39 | Unicode 40 | v142 41 | false 42 | false 43 | 44 | 45 | Application 46 | false 47 | true 48 | Unicode 49 | v142 50 | 51 | 52 | Application 53 | false 54 | true 55 | Unicode 56 | v142 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | $(Configuration)\ 77 | 78 | 79 | true 80 | 81 | 82 | false 83 | $(Configuration)\ 84 | 85 | 86 | false 87 | 88 | 89 | 90 | Use 91 | Level3 92 | Disabled 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | 95 | 96 | Console 97 | true 98 | $(OutDir)$(TargetName)$(TargetExt) 99 | 100 | 101 | 102 | 103 | Use 104 | Level3 105 | Disabled 106 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | 108 | 109 | Console 110 | true 111 | $(OutDir)$(TargetName)$(TargetExt) 112 | RequireAdministrator 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | Use 120 | MaxSpeed 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | MultiThreaded 125 | 126 | 127 | Console 128 | false 129 | true 130 | true 131 | ..\bin\$(TargetName)$(TargetExt) 132 | 133 | 134 | 135 | 136 | Level3 137 | Use 138 | MaxSpeed 139 | true 140 | true 141 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 142 | MultiThreaded 143 | 144 | 145 | Console 146 | false 147 | true 148 | true 149 | ..\bin\$(TargetName)$(TargetExt) 150 | AsInvoker 151 | false 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | NotUsing 163 | NotUsing 164 | NotUsing 165 | NotUsing 166 | 167 | 168 | 169 | Create 170 | Create 171 | Create 172 | Create 173 | 174 | 175 | NotUsing 176 | NotUsing 177 | NotUsing 178 | NotUsing 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /sFany/Service.cpp: -------------------------------------------------------------------------------- 1 | // Service.cpp : Defines the entry point for the console application. 2 | // 3 | #include 4 | #include 5 | 6 | #include "Service.h" 7 | 8 | using namespace std; 9 | 10 | #pragma warning(disable : 4996) 11 | 12 | /** Window Service **/ 13 | TCHAR pServiceName[MAX_PATH]; 14 | 15 | SERVICE_TABLE_ENTRY lpServiceStartTable[] = 16 | { 17 | {pServiceName, ServiceMain}, 18 | {NULL, NULL} 19 | }; 20 | 21 | SERVICE_STATUS_HANDLE hServiceStatusHandle; 22 | SERVICE_STATUS ServiceStatus; 23 | LPSERVICE_MAIN_FUNCTION UserServiceMain=NULL; 24 | LPSERVICE_USER_FUNCTION UserStopFunction=NULL; 25 | 26 | DWORD Install(const TCHAR* pPath, const TCHAR* pName) 27 | { 28 | DWORD dwReturn; 29 | SERVICE_DESCRIPTION sd; 30 | sd.lpDescription = TEXT("sFany: Run your command line programes as windows service."); 31 | 32 | WriteLog(TEXT("-->sFany Install Path=[%s] Name=[%s] error code = %d"), pPath, pName, GetLastError()); 33 | 34 | SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE); 35 | if (schSCManager==0) { 36 | dwReturn = GetLastError(); 37 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d"), dwReturn); 38 | return dwReturn; 39 | } 40 | 41 | SC_HANDLE schService = CreateService 42 | ( 43 | schSCManager, /* SCManager database */ 44 | pName, /* name of service */ 45 | pName, /* service name to display */ 46 | SERVICE_ALL_ACCESS, /* desired access */ 47 | SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS , /* service type */ 48 | SERVICE_AUTO_START, /* start type */ 49 | SERVICE_ERROR_NORMAL, /* error control type */ 50 | pPath, /* service's binary */ 51 | NULL, /* no load ordering group */ 52 | NULL, /* no tag identifier */ 53 | NULL, /* no dependencies */ 54 | NULL, /* LocalSystem account */ 55 | NULL 56 | ); /* no password */ 57 | 58 | if (schService==0) { 59 | WriteLog(TEXT("-->Service Failed to create service %s, error code = %d"), pName, GetLastError()); 60 | } else { 61 | ChangeServiceConfig2(schService, // handle to service 62 | SERVICE_CONFIG_DESCRIPTION, // change: description 63 | &sd); // new description 64 | 65 | WriteLog( TEXT("-->Service Service %s installed"), pName); 66 | CloseServiceHandle(schService); 67 | } 68 | return CloseServiceHandle(schSCManager); 69 | } 70 | 71 | VOID UnInstall(const TCHAR* pName) 72 | { 73 | SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 74 | if (schSCManager==0) 75 | { 76 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d"), GetLastError()); 77 | } 78 | else 79 | { 80 | SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS); 81 | if (schService==0) 82 | { 83 | WriteLog( TEXT("-->Service OpenService failed, error code = %d"), GetLastError()); 84 | } 85 | else 86 | { 87 | if(!DeleteService(schService)) 88 | { 89 | WriteLog(TEXT("-->Service Failed to delete service %s"), pName); 90 | } 91 | else 92 | { 93 | WriteLog(TEXT("-->Service Service %s removed"),pName); 94 | } 95 | CloseServiceHandle(schService); 96 | } 97 | CloseServiceHandle(schSCManager); 98 | } 99 | } 100 | 101 | BOOL KillService(const TCHAR* pName) 102 | { 103 | // kill service with given name 104 | SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 105 | if (schSCManager==0) 106 | { 107 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d"), GetLastError()); 108 | } 109 | else 110 | { 111 | // open the service 112 | SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS); 113 | if (schService==0) 114 | { 115 | WriteLog(TEXT("-->Service OpenService failed, error code = %d"), GetLastError()); 116 | } 117 | else 118 | { 119 | // call ControlService to kill the given service 120 | SERVICE_STATUS status; 121 | if(ControlService(schService,SERVICE_CONTROL_STOP,&status)) 122 | { 123 | CloseServiceHandle(schService); 124 | CloseServiceHandle(schSCManager); 125 | return TRUE; 126 | } 127 | else 128 | { 129 | WriteLog(TEXT("-->Service ControlService failed, error code = %d"), GetLastError()); 130 | } 131 | CloseServiceHandle(schService); 132 | } 133 | CloseServiceHandle(schSCManager); 134 | } 135 | return FALSE; 136 | } 137 | 138 | BOOL RunService(const TCHAR* pName) 139 | { 140 | // run service with given name 141 | SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 142 | if (schSCManager==0) 143 | { 144 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d line:%d"), GetLastError(),__LINE__); 145 | } 146 | else 147 | { 148 | // open the service 149 | SC_HANDLE schService = OpenService( schSCManager, pName, SERVICE_ALL_ACCESS); 150 | if (schService==0) 151 | { 152 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d line:%d"), GetLastError(), __LINE__); 153 | } 154 | else 155 | { 156 | // call StartService to run the service 157 | if(StartService(schService, 0, (const TCHAR**)NULL)) 158 | { 159 | CloseServiceHandle(schService); 160 | CloseServiceHandle(schSCManager); 161 | return TRUE; 162 | } 163 | else 164 | { 165 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d line:%d"), GetLastError(), __LINE__); 166 | } 167 | CloseServiceHandle(schService); 168 | } 169 | CloseServiceHandle(schSCManager); 170 | } 171 | return FALSE; 172 | } 173 | 174 | DWORD QueryService(const TCHAR* pName) { 175 | SERVICE_STATUS_PROCESS ssStatus; 176 | DWORD dwBytesNeeded; 177 | 178 | // Get a handle to the SCM database. 179 | 180 | SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE ); 181 | if (schSCManager==0) 182 | { 183 | WriteLog(TEXT("-->Service OpenSCManager failed, error code = %d line:%d"), GetLastError(), __LINE__); 184 | } 185 | else 186 | { 187 | // open the service 188 | SC_HANDLE schService = OpenService( schSCManager, pName, SC_MANAGER_ENUMERATE_SERVICE ); 189 | if (schService==0) 190 | { 191 | WriteLog(TEXT("-->Service OpenService failed, error code = %d line:%d"), GetLastError(), __LINE__); 192 | } 193 | else 194 | { 195 | // Check the status in case the service is not stopped. 196 | 197 | if (!QueryServiceStatusEx( 198 | schService, // handle to service 199 | SC_STATUS_PROCESS_INFO, // information level 200 | (LPBYTE) &ssStatus, // address of structure 201 | sizeof(SERVICE_STATUS_PROCESS), // size of structure 202 | &dwBytesNeeded ) ) // size needed if buffer is too small 203 | { 204 | WriteLog(TEXT("-->Service QueryServiceStatusEx failed (%d)"), GetLastError()); 205 | } else { 206 | CloseServiceHandle(schService); 207 | CloseServiceHandle(schSCManager); 208 | return ssStatus.dwCurrentState; 209 | } 210 | CloseServiceHandle(schService); 211 | } 212 | CloseServiceHandle(schSCManager); 213 | } 214 | return 0; 215 | } 216 | 217 | 218 | VOID ExecuteService(const TCHAR* pName,LPSERVICE_MAIN_FUNCTION UserFunc) 219 | { 220 | lpServiceStartTable[0].lpServiceName = (TCHAR*) pName; 221 | UserServiceMain=UserFunc; 222 | if(!StartServiceCtrlDispatcher(lpServiceStartTable)) 223 | { 224 | WriteLog(TEXT("-->Service StartServiceCtrlDispatcher failed, error code = %d"), GetLastError()); 225 | } 226 | } 227 | 228 | VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) 229 | { 230 | DWORD status = 0; 231 | DWORD specificError = 0xfffffff; 232 | 233 | ServiceStatus.dwServiceType = SERVICE_WIN32; 234 | ServiceStatus.dwCurrentState = SERVICE_START_PENDING; 235 | ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE; 236 | ServiceStatus.dwWin32ExitCode = 0; 237 | ServiceStatus.dwServiceSpecificExitCode = 0; 238 | ServiceStatus.dwCheckPoint = 0; 239 | ServiceStatus.dwWaitHint = 0; 240 | 241 | WriteLog(TEXT("-->Service ServiceMain start...")); 242 | 243 | hServiceStatusHandle = RegisterServiceCtrlHandler(pServiceName, ServiceHandler); 244 | if (hServiceStatusHandle==0) 245 | { 246 | WriteLog(TEXT("-->Service RegisterServiceCtrlHandler failed, error code = %d"), GetLastError()); 247 | return; 248 | } 249 | 250 | // Initialization complete - report running status 251 | ServiceStatus.dwCurrentState = SERVICE_RUNNING; 252 | ServiceStatus.dwCheckPoint = 0; 253 | ServiceStatus.dwWaitHint = 0; 254 | if(!SetServiceStatus(hServiceStatusHandle, &ServiceStatus)) 255 | { 256 | WriteLog(TEXT("-->Service SetServiceStatus failed, error code = %d"), GetLastError()); 257 | } 258 | 259 | if (UserServiceMain) { 260 | WriteLog(TEXT("-->Service callback UserServiceMain")); 261 | UserServiceMain(dwArgc, lpszArgv); 262 | } 263 | 264 | ServiceStatus.dwCurrentState = SERVICE_STOPPED; 265 | ServiceStatus.dwCheckPoint = 0; 266 | ServiceStatus.dwWaitHint = 0; 267 | if(!SetServiceStatus(hServiceStatusHandle, &ServiceStatus)) 268 | { 269 | WriteLog(TEXT("-->Service SetServiceStatus failed, error code = %d"), GetLastError()); 270 | } 271 | } 272 | 273 | VOID WINAPI ServiceHandler(DWORD fdwControl) 274 | { 275 | WriteLog(TEXT("-->Service ServiceHandle fdwControl: 0x%0X"),fdwControl); 276 | switch(fdwControl) 277 | { 278 | case SERVICE_CONTROL_STOP: 279 | case SERVICE_CONTROL_SHUTDOWN: 280 | ServiceStatus.dwWin32ExitCode = 0; 281 | ServiceStatus.dwCurrentState = SERVICE_STOPPED; 282 | ServiceStatus.dwCheckPoint = 0; 283 | ServiceStatus.dwWaitHint = 0; 284 | if (UserStopFunction) { 285 | UserStopFunction(fdwControl); 286 | } 287 | break; 288 | case SERVICE_CONTROL_PAUSE: 289 | ServiceStatus.dwCurrentState = SERVICE_PAUSED; 290 | break; 291 | case SERVICE_CONTROL_CONTINUE: 292 | ServiceStatus.dwCurrentState = SERVICE_RUNNING; 293 | break; 294 | case SERVICE_CONTROL_INTERROGATE: 295 | break; 296 | default: 297 | break; 298 | }; 299 | 300 | if (!SetServiceStatus(hServiceStatusHandle, &ServiceStatus)) 301 | { 302 | WriteLog(TEXT("-->Service SetServiceStatus failed, error code = %d"), GetLastError()); 303 | } 304 | } 305 | --------------------------------------------------------------------------------