From a2a19b533bbcdab37b7704a8b89a22069db39ec8 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Fri, 3 Oct 2025 14:52:01 +0200 Subject: zenutil cleanup (#550) * move referencemetadata to zenstore * rename zenutil/windows/service to windowsservice --- src/zenserver/main.cpp | 2 +- src/zenstore/cache/cachedisklayer.cpp | 3 +- src/zenstore/projectstore.cpp | 3 +- src/zenstore/referencemetadata.cpp | 32 ++ src/zenstore/referencemetadata.h | 109 ++++ src/zenutil/include/zenutil/referencemetadata.h | 109 ---- src/zenutil/include/zenutil/windows/service.h | 24 - .../include/zenutil/windows/windowsservice.h | 24 + src/zenutil/referencemetadata.cpp | 32 -- src/zenutil/service.cpp | 2 +- src/zenutil/windows/service.cpp | 639 --------------------- src/zenutil/windows/windowsservice.cpp | 639 +++++++++++++++++++++ 12 files changed, 810 insertions(+), 808 deletions(-) create mode 100644 src/zenstore/referencemetadata.cpp create mode 100644 src/zenstore/referencemetadata.h delete mode 100644 src/zenutil/include/zenutil/referencemetadata.h delete mode 100644 src/zenutil/include/zenutil/windows/service.h create mode 100644 src/zenutil/include/zenutil/windows/windowsservice.h delete mode 100644 src/zenutil/referencemetadata.cpp delete mode 100644 src/zenutil/windows/service.cpp create mode 100644 src/zenutil/windows/windowsservice.cpp diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp index d512d4894..a91c95ffb 100644 --- a/src/zenserver/main.cpp +++ b/src/zenserver/main.cpp @@ -31,7 +31,7 @@ #if ZEN_PLATFORM_WINDOWS # include -# include +# include #endif ////////////////////////////////////////////////////////////////////////// diff --git a/src/zenstore/cache/cachedisklayer.cpp b/src/zenstore/cache/cachedisklayer.cpp index fd92dfa5a..c2e811003 100644 --- a/src/zenstore/cache/cachedisklayer.cpp +++ b/src/zenstore/cache/cachedisklayer.cpp @@ -15,9 +15,10 @@ #include #include #include -#include #include +#include "../referencemetadata.h" + #include #include diff --git a/src/zenstore/projectstore.cpp b/src/zenstore/projectstore.cpp index f23a669b5..8ae74c8cf 100644 --- a/src/zenstore/projectstore.cpp +++ b/src/zenstore/projectstore.cpp @@ -18,9 +18,10 @@ #include #include #include -#include #include +#include "referencemetadata.h" + ZEN_THIRD_PARTY_INCLUDES_START #include #include diff --git a/src/zenstore/referencemetadata.cpp b/src/zenstore/referencemetadata.cpp new file mode 100644 index 000000000..e202b435b --- /dev/null +++ b/src/zenstore/referencemetadata.cpp @@ -0,0 +1,32 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "referencemetadata.h" +////////////////////////////////////////////////////////////////////////// + +#include + +namespace zen { + +uint32_t +ReferenceMetaDataHeader::ComputeChecksum() const +{ + return XXH32(&Magic, sizeof(ReferenceMetaDataHeader) - sizeof(uint32_t), 0xC0C0'BABA); +} + +bool +ReferenceMetaDataHeader::IsValid(uint32_t ExpectedMagic) const +{ + if (Magic != ExpectedMagic) + { + return false; + } + + if (Checksum != ComputeChecksum()) + { + return false; + } + + return true; +} + +} // namespace zen diff --git a/src/zenstore/referencemetadata.h b/src/zenstore/referencemetadata.h new file mode 100644 index 000000000..5160bfb8b --- /dev/null +++ b/src/zenstore/referencemetadata.h @@ -0,0 +1,109 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include + +ZEN_THIRD_PARTY_INCLUDES_START +#include +ZEN_THIRD_PARTY_INCLUDES_END + +namespace zen { + +#pragma pack(push) +#pragma pack(1) + +struct ReferenceMetaDataHeader +{ + static constexpr uint32_t Version1 = 1; + static constexpr uint32_t CurrentVersion = Version1; + + ReferenceMetaDataHeader(uint32_t InMagic, uint32_t InEntryCount, uint64_t InAttachmentCount) + : Magic(InMagic) + , EntryCount(InEntryCount) + , AttachmentCount(InAttachmentCount) + , Checksum(ComputeChecksum()) + { + } + + uint32_t Magic = 0xffffffffu; + uint32_t Version = CurrentVersion; + + uint32_t EntryCount = 0; + uint64_t AttachmentCount = 0; + uint64_t Padding = 0; + + uint32_t Checksum = 0; + + bool IsValid(uint32_t ExpectedMagic) const; + + template + static uint64_t ExpectedSize(uint32_t EntryCount, uint64_t AttachmentCount) + { + return sizeof(ReferenceMetaDataHeader) + sizeof(KeyType) * EntryCount + sizeof(uint32_t) * EntryCount + + sizeof(AttachmentType) * AttachmentCount; + } + + ReferenceMetaDataHeader() = delete; + +private: + uint32_t ComputeChecksum() const; +}; + +static_assert(sizeof(ReferenceMetaDataHeader) == 32); + +#pragma pack(pop) + +template +CompositeBuffer +BuildReferenceMetaData(uint32_t HeaderMagic, + std::span Keys, + std::span AttachmentCounts, + std::span Attachments) +{ + uint32_t KeyCount = gsl::narrow(Keys.size()); + + ReferenceMetaDataHeader Header(HeaderMagic, KeyCount, Attachments.size()); + return CompositeBuffer(std::vector{ + SharedBuffer(IoBuffer(IoBuffer::Clone, &Header, sizeof(ReferenceMetaDataHeader))), + SharedBuffer(IoBuffer(IoBuffer::Wrap, Keys.data(), sizeof(KeyType) * Keys.size())), + SharedBuffer(IoBuffer(IoBuffer::Wrap, AttachmentCounts.data(), sizeof(uint32_t) * AttachmentCounts.size())), + SharedBuffer(IoBuffer(IoBuffer::Wrap, Attachments.data(), sizeof(AttachmentType) * Attachments.size()))}); +} + +template +bool +GetAttachmentsFromMetaData(const IoBuffer& MetaData, + const uint32_t ExpectedHeaderMagic, + std::function Keys, + std::span AttachmentCounts, + std::span Attachments)>&& Parser) +{ + MemoryView PayloadView = MetaData.GetView(); + if (PayloadView.GetSize() >= sizeof(ReferenceMetaDataHeader)) + { + const ReferenceMetaDataHeader* Header = (const ReferenceMetaDataHeader*)PayloadView.GetData(); + if (Header->IsValid(ExpectedHeaderMagic)) + { + if (MetaData.GetSize() == + ReferenceMetaDataHeader::ExpectedSize(Header->EntryCount, Header->AttachmentCount)) + { + PayloadView.MidInline(sizeof(ReferenceMetaDataHeader)); + std::span PayloadKeys = {(const KeyType*)PayloadView.GetData(), Header->EntryCount}; + PayloadView.MidInline(sizeof(KeyType) * Header->EntryCount); + std::span PayloadAttachmentCounts = {(const uint32_t*)PayloadView.GetData(), Header->EntryCount}; + PayloadView.MidInline(sizeof(uint32_t) * Header->EntryCount); + std::span PayloadAttachments = {(const AttachmentType*)PayloadView.GetData(), + Header->AttachmentCount}; + PayloadView.MidInline(sizeof(AttachmentType) * Header->AttachmentCount); + ZEN_ASSERT(PayloadView.GetSize() == 0); + + Parser(PayloadKeys, PayloadAttachmentCounts, PayloadAttachments); + + return true; + } + } + } + return false; +} +} // namespace zen diff --git a/src/zenutil/include/zenutil/referencemetadata.h b/src/zenutil/include/zenutil/referencemetadata.h deleted file mode 100644 index 5160bfb8b..000000000 --- a/src/zenutil/include/zenutil/referencemetadata.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include - -ZEN_THIRD_PARTY_INCLUDES_START -#include -ZEN_THIRD_PARTY_INCLUDES_END - -namespace zen { - -#pragma pack(push) -#pragma pack(1) - -struct ReferenceMetaDataHeader -{ - static constexpr uint32_t Version1 = 1; - static constexpr uint32_t CurrentVersion = Version1; - - ReferenceMetaDataHeader(uint32_t InMagic, uint32_t InEntryCount, uint64_t InAttachmentCount) - : Magic(InMagic) - , EntryCount(InEntryCount) - , AttachmentCount(InAttachmentCount) - , Checksum(ComputeChecksum()) - { - } - - uint32_t Magic = 0xffffffffu; - uint32_t Version = CurrentVersion; - - uint32_t EntryCount = 0; - uint64_t AttachmentCount = 0; - uint64_t Padding = 0; - - uint32_t Checksum = 0; - - bool IsValid(uint32_t ExpectedMagic) const; - - template - static uint64_t ExpectedSize(uint32_t EntryCount, uint64_t AttachmentCount) - { - return sizeof(ReferenceMetaDataHeader) + sizeof(KeyType) * EntryCount + sizeof(uint32_t) * EntryCount + - sizeof(AttachmentType) * AttachmentCount; - } - - ReferenceMetaDataHeader() = delete; - -private: - uint32_t ComputeChecksum() const; -}; - -static_assert(sizeof(ReferenceMetaDataHeader) == 32); - -#pragma pack(pop) - -template -CompositeBuffer -BuildReferenceMetaData(uint32_t HeaderMagic, - std::span Keys, - std::span AttachmentCounts, - std::span Attachments) -{ - uint32_t KeyCount = gsl::narrow(Keys.size()); - - ReferenceMetaDataHeader Header(HeaderMagic, KeyCount, Attachments.size()); - return CompositeBuffer(std::vector{ - SharedBuffer(IoBuffer(IoBuffer::Clone, &Header, sizeof(ReferenceMetaDataHeader))), - SharedBuffer(IoBuffer(IoBuffer::Wrap, Keys.data(), sizeof(KeyType) * Keys.size())), - SharedBuffer(IoBuffer(IoBuffer::Wrap, AttachmentCounts.data(), sizeof(uint32_t) * AttachmentCounts.size())), - SharedBuffer(IoBuffer(IoBuffer::Wrap, Attachments.data(), sizeof(AttachmentType) * Attachments.size()))}); -} - -template -bool -GetAttachmentsFromMetaData(const IoBuffer& MetaData, - const uint32_t ExpectedHeaderMagic, - std::function Keys, - std::span AttachmentCounts, - std::span Attachments)>&& Parser) -{ - MemoryView PayloadView = MetaData.GetView(); - if (PayloadView.GetSize() >= sizeof(ReferenceMetaDataHeader)) - { - const ReferenceMetaDataHeader* Header = (const ReferenceMetaDataHeader*)PayloadView.GetData(); - if (Header->IsValid(ExpectedHeaderMagic)) - { - if (MetaData.GetSize() == - ReferenceMetaDataHeader::ExpectedSize(Header->EntryCount, Header->AttachmentCount)) - { - PayloadView.MidInline(sizeof(ReferenceMetaDataHeader)); - std::span PayloadKeys = {(const KeyType*)PayloadView.GetData(), Header->EntryCount}; - PayloadView.MidInline(sizeof(KeyType) * Header->EntryCount); - std::span PayloadAttachmentCounts = {(const uint32_t*)PayloadView.GetData(), Header->EntryCount}; - PayloadView.MidInline(sizeof(uint32_t) * Header->EntryCount); - std::span PayloadAttachments = {(const AttachmentType*)PayloadView.GetData(), - Header->AttachmentCount}; - PayloadView.MidInline(sizeof(AttachmentType) * Header->AttachmentCount); - ZEN_ASSERT(PayloadView.GetSize() == 0); - - Parser(PayloadKeys, PayloadAttachmentCounts, PayloadAttachments); - - return true; - } - } - } - return false; -} -} // namespace zen diff --git a/src/zenutil/include/zenutil/windows/service.h b/src/zenutil/include/zenutil/windows/service.h deleted file mode 100644 index ca0270a36..000000000 --- a/src/zenutil/include/zenutil/windows/service.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include - -class WindowsService -{ -public: - WindowsService(); - ~WindowsService(); - - virtual int Run() = 0; - - int ServiceMain(); - - static void Install(); - static void Delete(); - - int SvcMain(); - static void __stdcall SvcCtrlHandler(unsigned long); -}; - -VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint); diff --git a/src/zenutil/include/zenutil/windows/windowsservice.h b/src/zenutil/include/zenutil/windows/windowsservice.h new file mode 100644 index 000000000..ca0270a36 --- /dev/null +++ b/src/zenutil/include/zenutil/windows/windowsservice.h @@ -0,0 +1,24 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include + +class WindowsService +{ +public: + WindowsService(); + ~WindowsService(); + + virtual int Run() = 0; + + int ServiceMain(); + + static void Install(); + static void Delete(); + + int SvcMain(); + static void __stdcall SvcCtrlHandler(unsigned long); +}; + +VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint); diff --git a/src/zenutil/referencemetadata.cpp b/src/zenutil/referencemetadata.cpp deleted file mode 100644 index bbcafcfba..000000000 --- a/src/zenutil/referencemetadata.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include -////////////////////////////////////////////////////////////////////////// - -#include - -namespace zen { - -uint32_t -ReferenceMetaDataHeader::ComputeChecksum() const -{ - return XXH32(&Magic, sizeof(ReferenceMetaDataHeader) - sizeof(uint32_t), 0xC0C0'BABA); -} - -bool -ReferenceMetaDataHeader::IsValid(uint32_t ExpectedMagic) const -{ - if (Magic != ExpectedMagic) - { - return false; - } - - if (Checksum != ComputeChecksum()) - { - return false; - } - - return true; -} - -} // namespace zen diff --git a/src/zenutil/service.cpp b/src/zenutil/service.cpp index e4a9a951e..103fdaa2f 100644 --- a/src/zenutil/service.cpp +++ b/src/zenutil/service.cpp @@ -10,7 +10,7 @@ #if ZEN_PLATFORM_WINDOWS # include -# include +# include #endif #if ZEN_PLATFORM_MAC # include diff --git a/src/zenutil/windows/service.cpp b/src/zenutil/windows/service.cpp deleted file mode 100644 index b76ed7a66..000000000 --- a/src/zenutil/windows/service.cpp +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include - -#if ZEN_PLATFORM_WINDOWS -# include - -# include -# include - -# include -# include -# include - -# define SVCNAME L"Zen Store" - -SERVICE_STATUS gSvcStatus; -SERVICE_STATUS_HANDLE gSvcStatusHandle; -HANDLE ghSvcStopEvent = NULL; - -void SvcInstall(void); - -void SvcReportEvent(LPTSTR); - -WindowsService::WindowsService() -{ -} - -WindowsService::~WindowsService() -{ -} - -// -// Purpose: -// Installs a service in the SCM database -// -// Parameters: -// None -// -// Return value: -// None -// -VOID -WindowsService::Install() -{ - SC_HANDLE schSCManager; - SC_HANDLE schService; - TCHAR szPath[MAX_PATH]; - - if (!GetModuleFileName(NULL, szPath, MAX_PATH)) - { - printf("Cannot install service (%d)\n", GetLastError()); - 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - 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 - 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()); - CloseServiceHandle(schSCManager); - return; - } - else - printf("Service installed successfully\n"); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} - -void -WindowsService::Delete() -{ - SC_HANDLE schSCManager; - SC_HANDLE schService; - - // 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - // Get a handle to the service. - - schService = OpenService(schSCManager, // SCM database - SVCNAME, // name of service - DELETE); // need delete access - - if (schService == NULL) - { - printf("OpenService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - - // Delete the service. - - if (!DeleteService(schService)) - { - printf("DeleteService failed (%d)\n", GetLastError()); - } - else - printf("Service deleted successfully\n"); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} - -WindowsService* gSvc; - -void WINAPI -CallMain(DWORD, LPSTR*) -{ - gSvc->SvcMain(); -} - -int -WindowsService::ServiceMain() -{ - zen::SetCurrentThreadName("svc-main"); - - gSvc = this; - - SERVICE_TABLE_ENTRY DispatchTable[] = {{(LPWSTR)SVCNAME, (LPSERVICE_MAIN_FUNCTION)&CallMain}, {NULL, NULL}}; - - // This call returns when the service has stopped. - // The process should simply terminate when the call returns. - - if (!StartServiceCtrlDispatcher(DispatchTable)) - { - const DWORD dwError = zen::GetLastError(); - - if (dwError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) - { - // Not actually running as a service - gSvc = nullptr; - - zen::SetIsInteractiveSession(true); - - return Run(); - } - else - { - zen::ThrowSystemError(dwError, "StartServiceCtrlDispatcher failed"); - } - } - - zen::SetIsInteractiveSession(false); - - return zen::ApplicationExitCode(); -} - -int -WindowsService::SvcMain() -{ - // Register the handler function for the service - - gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME, SvcCtrlHandler); - - if (!gSvcStatusHandle) - { - SvcReportEvent((LPTSTR)TEXT("RegisterServiceCtrlHandler")); - - return 1; - } - - // These SERVICE_STATUS members remain as set here - - gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - gSvcStatus.dwServiceSpecificExitCode = 0; - - // Report initial status to the SCM - - ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); - - // Create an event. The control handler function, SvcCtrlHandler, - // signals this event when it receives the stop control code. - - ghSvcStopEvent = CreateEvent(NULL, // default security attributes - TRUE, // manual reset event - FALSE, // not signaled - NULL); // no name - - if (ghSvcStopEvent == NULL) - { - ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 0); - - return 1; - } - - int ReturnCode = Run(); - return ReturnCode; -} - -// -// Purpose: -// Retrieves and displays the current service configuration. -// -// Parameters: -// None -// -// Return value: -// None -// -void -DoQuerySvc() -{ - SC_HANDLE schSCManager{}; - SC_HANDLE schService{}; - LPQUERY_SERVICE_CONFIG lpsc{}; - LPSERVICE_DESCRIPTION lpsd{}; - DWORD dwBytesNeeded{}, cbBufSize{}, dwError{}; - - // 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - // Get a handle to the service. - - schService = OpenService(schSCManager, // SCM database - SVCNAME, // name of service - SERVICE_QUERY_CONFIG); // need query config access - - if (schService == NULL) - { - printf("OpenService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - - // Get the configuration information. - - if (!QueryServiceConfig(schService, NULL, 0, &dwBytesNeeded)) - { - dwError = GetLastError(); - if (ERROR_INSUFFICIENT_BUFFER == dwError) - { - cbBufSize = dwBytesNeeded; - lpsc = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, cbBufSize); - } - else - { - printf("QueryServiceConfig failed (%d)", dwError); - goto cleanup; - } - } - - if (!QueryServiceConfig(schService, lpsc, cbBufSize, &dwBytesNeeded)) - { - printf("QueryServiceConfig failed (%d)", GetLastError()); - goto cleanup; - } - - if (!QueryServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded)) - { - dwError = GetLastError(); - if (ERROR_INSUFFICIENT_BUFFER == dwError) - { - cbBufSize = dwBytesNeeded; - lpsd = (LPSERVICE_DESCRIPTION)LocalAlloc(LMEM_FIXED, cbBufSize); - } - else - { - printf("QueryServiceConfig2 failed (%d)", dwError); - goto cleanup; - } - } - - if (!QueryServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, cbBufSize, &dwBytesNeeded)) - { - printf("QueryServiceConfig2 failed (%d)", GetLastError()); - goto cleanup; - } - - // Print the configuration information. - - _tprintf(TEXT("%s configuration: \n"), SVCNAME); - _tprintf(TEXT(" Type: 0x%x\n"), lpsc->dwServiceType); - _tprintf(TEXT(" Start Type: 0x%x\n"), lpsc->dwStartType); - _tprintf(TEXT(" Error Control: 0x%x\n"), lpsc->dwErrorControl); - _tprintf(TEXT(" Binary path: %s\n"), lpsc->lpBinaryPathName); - _tprintf(TEXT(" Account: %s\n"), lpsc->lpServiceStartName); - - if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, TEXT("")) != 0) - _tprintf(TEXT(" Description: %s\n"), lpsd->lpDescription); - if (lpsc->lpLoadOrderGroup != NULL && lstrcmp(lpsc->lpLoadOrderGroup, TEXT("")) != 0) - _tprintf(TEXT(" Load order group: %s\n"), lpsc->lpLoadOrderGroup); - if (lpsc->dwTagId != 0) - _tprintf(TEXT(" Tag ID: %d\n"), lpsc->dwTagId); - if (lpsc->lpDependencies != NULL && lstrcmp(lpsc->lpDependencies, TEXT("")) != 0) - _tprintf(TEXT(" Dependencies: %s\n"), lpsc->lpDependencies); - - LocalFree(lpsc); - LocalFree(lpsd); - -cleanup: - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} - -// -// Purpose: -// Disables the service. -// -// Parameters: -// None -// -// Return value: -// None -// -void -DoDisableSvc() -{ - SC_HANDLE schSCManager; - SC_HANDLE schService; - - // 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - // Get a handle to the service. - - schService = OpenService(schSCManager, // SCM database - SVCNAME, // name of service - SERVICE_CHANGE_CONFIG); // need change config access - - if (schService == NULL) - { - printf("OpenService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - - // Change the service start type. - - if (!ChangeServiceConfig(schService, // handle of service - SERVICE_NO_CHANGE, // service type: no change - SERVICE_DISABLED, // service start type - SERVICE_NO_CHANGE, // error control: no change - NULL, // binary path: no change - NULL, // load order group: no change - NULL, // tag ID: no change - NULL, // dependencies: no change - NULL, // account name: no change - NULL, // password: no change - NULL)) // display name: no change - { - printf("ChangeServiceConfig failed (%d)\n", GetLastError()); - } - else - printf("Service disabled successfully.\n"); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} - -// -// Purpose: -// Enables the service. -// -// Parameters: -// None -// -// Return value: -// None -// -VOID __stdcall DoEnableSvc() -{ - SC_HANDLE schSCManager; - SC_HANDLE schService; - - // 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - // Get a handle to the service. - - schService = OpenService(schSCManager, // SCM database - SVCNAME, // name of service - SERVICE_CHANGE_CONFIG); // need change config access - - if (schService == NULL) - { - printf("OpenService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - - // Change the service start type. - - if (!ChangeServiceConfig(schService, // handle of service - SERVICE_NO_CHANGE, // service type: no change - SERVICE_DEMAND_START, // service start type - SERVICE_NO_CHANGE, // error control: no change - NULL, // binary path: no change - NULL, // load order group: no change - NULL, // tag ID: no change - NULL, // dependencies: no change - NULL, // account name: no change - NULL, // password: no change - NULL)) // display name: no change - { - printf("ChangeServiceConfig failed (%d)\n", GetLastError()); - } - else - printf("Service enabled successfully.\n"); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} -// -// Purpose: -// Updates the service description to "This is a test description". -// -// Parameters: -// None -// -// Return value: -// None -// -void -DoUpdateSvcDesc() -{ - SC_HANDLE schSCManager; - SC_HANDLE schService; - SERVICE_DESCRIPTION sd; - TCHAR szDesc[] = TEXT("This is a test description"); - - // 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) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - // Get a handle to the service. - - schService = OpenService(schSCManager, // SCM database - SVCNAME, // name of service - SERVICE_CHANGE_CONFIG); // need change config access - - if (schService == NULL) - { - printf("OpenService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - - // Change the service description. - - sd.lpDescription = szDesc; - - if (!ChangeServiceConfig2(schService, // handle to service - SERVICE_CONFIG_DESCRIPTION, // change: description - &sd)) // new description - { - printf("ChangeServiceConfig2 failed\n"); - } - else - printf("Service description updated successfully.\n"); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); -} - -// -// Purpose: -// Sets the current service status and reports it to the SCM. -// -// Parameters: -// dwCurrentState - The current state (see SERVICE_STATUS) -// dwWin32ExitCode - The system error code -// dwWaitHint - Estimated time for pending operation, -// in milliseconds -// -// Return value: -// None -// -VOID -ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) -{ - static DWORD dwCheckPoint = 1; - - // Fill in the SERVICE_STATUS structure. - - gSvcStatus.dwCurrentState = dwCurrentState; - gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; - gSvcStatus.dwWaitHint = dwWaitHint; - - if (dwCurrentState == SERVICE_START_PENDING) - gSvcStatus.dwControlsAccepted = 0; - else - gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - - if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) - gSvcStatus.dwCheckPoint = 0; - else - gSvcStatus.dwCheckPoint = dwCheckPoint++; - - // Report the status of the service to the SCM. - SetServiceStatus(gSvcStatusHandle, &gSvcStatus); -} - -void -WindowsService::SvcCtrlHandler(DWORD dwCtrl) -{ - // Handle the requested control code. - // - // Called by SCM whenever a control code is sent to the service - // using the ControlService function. - - switch (dwCtrl) - { - case SERVICE_CONTROL_STOP: - ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); - - // Signal the service to stop. - - SetEvent(ghSvcStopEvent); - zen::RequestApplicationExit(0); - - ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0); - return; - - case SERVICE_CONTROL_INTERROGATE: - break; - - default: - break; - } -} - -// -// Purpose: -// Logs messages to the event log -// -// Parameters: -// szFunction - name of function that failed -// -// Return value: -// None -// -// Remarks: -// The service must have an entry in the Application event log. -// -VOID -SvcReportEvent(LPTSTR szFunction) -{ - ZEN_UNUSED(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, // 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); - //} -} - -#endif // ZEN_PLATFORM_WINDOWS diff --git a/src/zenutil/windows/windowsservice.cpp b/src/zenutil/windows/windowsservice.cpp new file mode 100644 index 000000000..ebb88b018 --- /dev/null +++ b/src/zenutil/windows/windowsservice.cpp @@ -0,0 +1,639 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include + +#if ZEN_PLATFORM_WINDOWS +# include + +# include +# include + +# include +# include +# include + +# define SVCNAME L"Zen Store" + +SERVICE_STATUS gSvcStatus; +SERVICE_STATUS_HANDLE gSvcStatusHandle; +HANDLE ghSvcStopEvent = NULL; + +void SvcInstall(void); + +void SvcReportEvent(LPTSTR); + +WindowsService::WindowsService() +{ +} + +WindowsService::~WindowsService() +{ +} + +// +// Purpose: +// Installs a service in the SCM database +// +// Parameters: +// None +// +// Return value: +// None +// +VOID +WindowsService::Install() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + TCHAR szPath[MAX_PATH]; + + if (!GetModuleFileName(NULL, szPath, MAX_PATH)) + { + printf("Cannot install service (%d)\n", GetLastError()); + 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + 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 + 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()); + CloseServiceHandle(schSCManager); + return; + } + else + printf("Service installed successfully\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +void +WindowsService::Delete() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + + // 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + // Get a handle to the service. + + schService = OpenService(schSCManager, // SCM database + SVCNAME, // name of service + DELETE); // need delete access + + if (schService == NULL) + { + printf("OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // Delete the service. + + if (!DeleteService(schService)) + { + printf("DeleteService failed (%d)\n", GetLastError()); + } + else + printf("Service deleted successfully\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +WindowsService* gSvc; + +void WINAPI +CallMain(DWORD, LPSTR*) +{ + gSvc->SvcMain(); +} + +int +WindowsService::ServiceMain() +{ + zen::SetCurrentThreadName("svc-main"); + + gSvc = this; + + SERVICE_TABLE_ENTRY DispatchTable[] = {{(LPWSTR)SVCNAME, (LPSERVICE_MAIN_FUNCTION)&CallMain}, {NULL, NULL}}; + + // This call returns when the service has stopped. + // The process should simply terminate when the call returns. + + if (!StartServiceCtrlDispatcher(DispatchTable)) + { + const DWORD dwError = zen::GetLastError(); + + if (dwError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) + { + // Not actually running as a service + gSvc = nullptr; + + zen::SetIsInteractiveSession(true); + + return Run(); + } + else + { + zen::ThrowSystemError(dwError, "StartServiceCtrlDispatcher failed"); + } + } + + zen::SetIsInteractiveSession(false); + + return zen::ApplicationExitCode(); +} + +int +WindowsService::SvcMain() +{ + // Register the handler function for the service + + gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME, SvcCtrlHandler); + + if (!gSvcStatusHandle) + { + SvcReportEvent((LPTSTR)TEXT("RegisterServiceCtrlHandler")); + + return 1; + } + + // These SERVICE_STATUS members remain as set here + + gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + gSvcStatus.dwServiceSpecificExitCode = 0; + + // Report initial status to the SCM + + ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); + + // Create an event. The control handler function, SvcCtrlHandler, + // signals this event when it receives the stop control code. + + ghSvcStopEvent = CreateEvent(NULL, // default security attributes + TRUE, // manual reset event + FALSE, // not signaled + NULL); // no name + + if (ghSvcStopEvent == NULL) + { + ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 0); + + return 1; + } + + int ReturnCode = Run(); + return ReturnCode; +} + +// +// Purpose: +// Retrieves and displays the current service configuration. +// +// Parameters: +// None +// +// Return value: +// None +// +void +DoQuerySvc() +{ + SC_HANDLE schSCManager{}; + SC_HANDLE schService{}; + LPQUERY_SERVICE_CONFIG lpsc{}; + LPSERVICE_DESCRIPTION lpsd{}; + DWORD dwBytesNeeded{}, cbBufSize{}, dwError{}; + + // 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + // Get a handle to the service. + + schService = OpenService(schSCManager, // SCM database + SVCNAME, // name of service + SERVICE_QUERY_CONFIG); // need query config access + + if (schService == NULL) + { + printf("OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // Get the configuration information. + + if (!QueryServiceConfig(schService, NULL, 0, &dwBytesNeeded)) + { + dwError = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER == dwError) + { + cbBufSize = dwBytesNeeded; + lpsc = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, cbBufSize); + } + else + { + printf("QueryServiceConfig failed (%d)", dwError); + goto cleanup; + } + } + + if (!QueryServiceConfig(schService, lpsc, cbBufSize, &dwBytesNeeded)) + { + printf("QueryServiceConfig failed (%d)", GetLastError()); + goto cleanup; + } + + if (!QueryServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwBytesNeeded)) + { + dwError = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER == dwError) + { + cbBufSize = dwBytesNeeded; + lpsd = (LPSERVICE_DESCRIPTION)LocalAlloc(LMEM_FIXED, cbBufSize); + } + else + { + printf("QueryServiceConfig2 failed (%d)", dwError); + goto cleanup; + } + } + + if (!QueryServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)lpsd, cbBufSize, &dwBytesNeeded)) + { + printf("QueryServiceConfig2 failed (%d)", GetLastError()); + goto cleanup; + } + + // Print the configuration information. + + _tprintf(TEXT("%s configuration: \n"), SVCNAME); + _tprintf(TEXT(" Type: 0x%x\n"), lpsc->dwServiceType); + _tprintf(TEXT(" Start Type: 0x%x\n"), lpsc->dwStartType); + _tprintf(TEXT(" Error Control: 0x%x\n"), lpsc->dwErrorControl); + _tprintf(TEXT(" Binary path: %s\n"), lpsc->lpBinaryPathName); + _tprintf(TEXT(" Account: %s\n"), lpsc->lpServiceStartName); + + if (lpsd->lpDescription != NULL && lstrcmp(lpsd->lpDescription, TEXT("")) != 0) + _tprintf(TEXT(" Description: %s\n"), lpsd->lpDescription); + if (lpsc->lpLoadOrderGroup != NULL && lstrcmp(lpsc->lpLoadOrderGroup, TEXT("")) != 0) + _tprintf(TEXT(" Load order group: %s\n"), lpsc->lpLoadOrderGroup); + if (lpsc->dwTagId != 0) + _tprintf(TEXT(" Tag ID: %d\n"), lpsc->dwTagId); + if (lpsc->lpDependencies != NULL && lstrcmp(lpsc->lpDependencies, TEXT("")) != 0) + _tprintf(TEXT(" Dependencies: %s\n"), lpsc->lpDependencies); + + LocalFree(lpsc); + LocalFree(lpsd); + +cleanup: + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +// +// Purpose: +// Disables the service. +// +// Parameters: +// None +// +// Return value: +// None +// +void +DoDisableSvc() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + + // 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + // Get a handle to the service. + + schService = OpenService(schSCManager, // SCM database + SVCNAME, // name of service + SERVICE_CHANGE_CONFIG); // need change config access + + if (schService == NULL) + { + printf("OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // Change the service start type. + + if (!ChangeServiceConfig(schService, // handle of service + SERVICE_NO_CHANGE, // service type: no change + SERVICE_DISABLED, // service start type + SERVICE_NO_CHANGE, // error control: no change + NULL, // binary path: no change + NULL, // load order group: no change + NULL, // tag ID: no change + NULL, // dependencies: no change + NULL, // account name: no change + NULL, // password: no change + NULL)) // display name: no change + { + printf("ChangeServiceConfig failed (%d)\n", GetLastError()); + } + else + printf("Service disabled successfully.\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +// +// Purpose: +// Enables the service. +// +// Parameters: +// None +// +// Return value: +// None +// +VOID __stdcall DoEnableSvc() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + + // 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + // Get a handle to the service. + + schService = OpenService(schSCManager, // SCM database + SVCNAME, // name of service + SERVICE_CHANGE_CONFIG); // need change config access + + if (schService == NULL) + { + printf("OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // Change the service start type. + + if (!ChangeServiceConfig(schService, // handle of service + SERVICE_NO_CHANGE, // service type: no change + SERVICE_DEMAND_START, // service start type + SERVICE_NO_CHANGE, // error control: no change + NULL, // binary path: no change + NULL, // load order group: no change + NULL, // tag ID: no change + NULL, // dependencies: no change + NULL, // account name: no change + NULL, // password: no change + NULL)) // display name: no change + { + printf("ChangeServiceConfig failed (%d)\n", GetLastError()); + } + else + printf("Service enabled successfully.\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} +// +// Purpose: +// Updates the service description to "This is a test description". +// +// Parameters: +// None +// +// Return value: +// None +// +void +DoUpdateSvcDesc() +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + SERVICE_DESCRIPTION sd; + TCHAR szDesc[] = TEXT("This is a test description"); + + // 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) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + // Get a handle to the service. + + schService = OpenService(schSCManager, // SCM database + SVCNAME, // name of service + SERVICE_CHANGE_CONFIG); // need change config access + + if (schService == NULL) + { + printf("OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // Change the service description. + + sd.lpDescription = szDesc; + + if (!ChangeServiceConfig2(schService, // handle to service + SERVICE_CONFIG_DESCRIPTION, // change: description + &sd)) // new description + { + printf("ChangeServiceConfig2 failed\n"); + } + else + printf("Service description updated successfully.\n"); + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +// +// Purpose: +// Sets the current service status and reports it to the SCM. +// +// Parameters: +// dwCurrentState - The current state (see SERVICE_STATUS) +// dwWin32ExitCode - The system error code +// dwWaitHint - Estimated time for pending operation, +// in milliseconds +// +// Return value: +// None +// +VOID +ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) +{ + static DWORD dwCheckPoint = 1; + + // Fill in the SERVICE_STATUS structure. + + gSvcStatus.dwCurrentState = dwCurrentState; + gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; + gSvcStatus.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + gSvcStatus.dwControlsAccepted = 0; + else + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) + gSvcStatus.dwCheckPoint = 0; + else + gSvcStatus.dwCheckPoint = dwCheckPoint++; + + // Report the status of the service to the SCM. + SetServiceStatus(gSvcStatusHandle, &gSvcStatus); +} + +void +WindowsService::SvcCtrlHandler(DWORD dwCtrl) +{ + // Handle the requested control code. + // + // Called by SCM whenever a control code is sent to the service + // using the ControlService function. + + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: + ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); + + // Signal the service to stop. + + SetEvent(ghSvcStopEvent); + zen::RequestApplicationExit(0); + + ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0); + return; + + case SERVICE_CONTROL_INTERROGATE: + break; + + default: + break; + } +} + +// +// Purpose: +// Logs messages to the event log +// +// Parameters: +// szFunction - name of function that failed +// +// Return value: +// None +// +// Remarks: +// The service must have an entry in the Application event log. +// +VOID +SvcReportEvent(LPTSTR szFunction) +{ + ZEN_UNUSED(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, // 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); + //} +} + +#endif // ZEN_PLATFORM_WINDOWS -- cgit v1.2.3