開源C++ Windows Server程式
阿新 • • 發佈:2018-12-19
目的
由於Windows C++ 沒有現成的Windows server程式的開發框架,而C#則有,所以為了方便大家以及我以後使用C++更方便的開發Windows server程式,特意寫此文。
主要程式碼如下
CppWindowsService.cpp檔案
#pragma region Includes #include <stdio.h> #include <windows.h> #include "ServiceInstaller.h" #include "ServiceBase.h" #include "SampleService.h" #pragma endregion // Internal name of the service #define SERVICE_NAME L"CppWindowsService" // Displayed name of the service #define SERVICE_DISPLAY_NAME L"CppWindowsService Sample Service" // Service start options. #define SERVICE_START_TYPE SERVICE_AUTO_START // List of service dependencies - "dep1\0dep2\0\0" #define SERVICE_DEPENDENCIES L"" // The name of the account under which the service should run #define SERVICE_ACCOUNT L"NT AUTHORITY\\LocalService" // The password to the service account name #define SERVICE_PASSWORD NULL // // FUNCTION: wmain(int, wchar_t *[]) // // PURPOSE: entrypoint for the application. // // PARAMETERS: // argc - number of command line arguments // argv - array of command line arguments // // RETURN VALUE: // none // // COMMENTS: // wmain() either performs the command line task, or run the service. // int wmain(int argc, wchar_t *argv[]) { //MessageBoxA(nullptr, "1", "1", MB_OK); if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/')))) { if (_wcsicmp(L"install", argv[1] + 1) == 0) { // Install the service when the command is // "-install" or "/install". InstallService( SERVICE_NAME, // Name of service SERVICE_DISPLAY_NAME, // Name to display SERVICE_START_TYPE, // Service start type SERVICE_DEPENDENCIES, // Dependencies SERVICE_ACCOUNT, // Service running account SERVICE_PASSWORD // Password of the account ); //MessageBoxA(nullptr, "install", "install", MB_OK); } else if (_wcsicmp(L"remove", argv[1] + 1) == 0) { // Uninstall the service when the command is // "-remove" or "/remove". UninstallService(SERVICE_NAME); //MessageBoxA(nullptr, "remove", "remove", MB_OK); } } else { wprintf(L"Parameters:\n"); wprintf(L" -install to install the service.\n"); wprintf(L" -remove to remove the service.\n"); CSampleService service(SERVICE_NAME); if (!CServiceBase::Run(service)) { wprintf(L"Service failed to run w/err 0x%08lx\n", GetLastError()); } //MessageBoxA(nullptr, "run", "run", MB_OK); } return 0; }
ServiceInstaller.cpp檔案
#pragma region "Includes" #include <stdio.h> #include <windows.h> #include "ServiceInstaller.h" #pragma endregion // // 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. // // 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(PWSTR pszServiceName, PWSTR pszDisplayName, DWORD dwStartType, PWSTR pszDependencies, PWSTR pszAccount, PWSTR pszPassword) { wchar_t szPath[MAX_PATH]; SC_HANDLE schSCManager = NULL; SC_HANDLE schService = NULL; if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0) { wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } // Open the local default service control manager database schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); if (schSCManager == NULL) { wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } // Install the service into SCM by calling CreateService schService = CreateService( schSCManager, // SCManager database pszServiceName, // Name of service pszDisplayName, // Name to display SERVICE_QUERY_STATUS, // Desired access SERVICE_WIN32_OWN_PROCESS, // Service type dwStartType, // Service start type SERVICE_ERROR_NORMAL, // Error control type szPath, // Service's binary NULL, // No load ordering group NULL, // No tag identifier pszDependencies, // Dependencies pszAccount, // Service running account pszPassword // Password of the account ); if (schService == NULL) { wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } wprintf(L"%s is installed.\n", pszServiceName); Cleanup: // Centralized cleanup for all allocated resources. if (schSCManager) { CloseServiceHandle(schSCManager); schSCManager = NULL; } if (schService) { CloseServiceHandle(schService); schService = 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(PWSTR pszServiceName) { SC_HANDLE schSCManager = NULL; SC_HANDLE schService = NULL; SERVICE_STATUS ssSvcStatus = {}; // Open the local default service control manager database schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager == NULL) { wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } // Open the service with delete, stop, and query status permissions schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE); if (schService == NULL) { wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } // Try to stop the service if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus)) { wprintf(L"Stopping %s.", pszServiceName); Sleep(1000); while (QueryServiceStatus(schService, &ssSvcStatus)) { if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) { wprintf(L"."); Sleep(1000); } else break; } if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED) { wprintf(L"\n%s is stopped.\n", pszServiceName); } else { wprintf(L"\n%s failed to stop.\n", pszServiceName); } } // Now remove the service by calling DeleteService. if (!DeleteService(schService)) { wprintf(L"DeleteService failed w/err 0x%08lx\n", GetLastError()); goto Cleanup; } wprintf(L"%s is removed.\n", pszServiceName); Cleanup: // Centralized cleanup for all allocated resources. if (schSCManager) { CloseServiceHandle(schSCManager); schSCManager = NULL; } if (schService) { CloseServiceHandle(schService); schService = NULL; } }
SampleService.cpp
這個類也是自己要實現的功能,根據自己的需要來定義函式即可。
#pragma region Includes #include "SampleService.h" #include "ThreadPool.h" #pragma endregion CSampleService::CSampleService(PWSTR pszServiceName, BOOL fCanStop, BOOL fCanShutdown, BOOL fCanPauseContinue) : CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue) { m_fStopping = FALSE; // Create a manual-reset event that is not signaled at first to indicate // the stopped signal of the service. m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hStoppedEvent == NULL) { throw GetLastError(); } } CSampleService::~CSampleService(void) { if (m_hStoppedEvent) { CloseHandle(m_hStoppedEvent); m_hStoppedEvent = NULL; } } // // FUNCTION: CSampleService::OnStart(DWORD, LPWSTR *) // // PURPOSE: The function is executed when a Start command is sent to the // service by the SCM or when the operating system starts (for a service // that starts automatically). It specifies actions to take when the // service starts. In this code sample, OnStart logs a service-start // message to the Application log, and queues the main service function for // execution in a thread pool worker thread. // // PARAMETERS: // * dwArgc - number of command line arguments // * lpszArgv - array of command line arguments // // NOTE: A service application is designed to be long running. Therefore, // it usually polls or monitors something in the system. The monitoring is // set up in the OnStart method. However, OnStart does not actually do the // monitoring. The OnStart method must return to the operating system after // the service's operation has begun. It must not loop forever or block. To // set up a simple monitoring mechanism, one general solution is to create // a timer in OnStart. The timer would then raise events in your code // periodically, at which time your service could do its monitoring. The // other solution is to spawn a new thread to perform the main service // functions, which is demonstrated in this code sample. // void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv) { // Log a service start message to the Application log. WriteEventLogEntry(L"CppWindowsService in OnStart", EVENTLOG_INFORMATION_TYPE); //MessageBoxA(nullptr, "OnStart", "OnStart", MB_OK); // Queue the main service function for execution in a worker thread. CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this); } // // FUNCTION: CSampleService::ServiceWorkerThread(void) // // PURPOSE: The method performs the main function of the service. It runs // on a thread pool worker thread. // void CSampleService::ServiceWorkerThread(void) { // Periodically check if the service is stopping. while (!m_fStopping) { // Perform main service function here... ::Sleep(2000); // Simulate some lengthy operations. } // Signal the stopped event. SetEvent(m_hStoppedEvent); } // // FUNCTION: CSampleService::OnStop(void) // // PURPOSE: The function is executed when a Stop command is sent to the // service by SCM. It specifies actions to take when a service stops // running. In this code sample, OnStop logs a service-stop message to the // Application log, and waits for the finish of the main service function. // // COMMENTS: // Be sure to periodically call ReportServiceStatus() with // SERVICE_STOP_PENDING if the procedure is going to take long time. // void CSampleService::OnStop() { // Log a service stop message to the Application log. WriteEventLogEntry(L"CppWindowsService in OnStop", EVENTLOG_INFORMATION_TYPE); //MessageBoxA(nullptr, "OnStop", "OnStop", MB_OK); // Indicate that the service is stopping and wait for the finish of the // main service function (ServiceWorkerThread). m_fStopping = TRUE; if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0) { throw GetLastError(); } }
注意點
服務程式一定不能放到桌面上,因為所有的服務程式起痘都是在桌面程式起痘之前,所以如果放到桌面上,將會導致載入不到該檔案,提示檔案被拒絕。