diff options
-rw-r--r-- | CMakeLists.txt | 18 | ||||
-rw-r--r-- | CONTRIBUTING.md | 2 | ||||
-rw-r--r-- | Install/MCServer_high_detail_debug.cmd | 2 | ||||
-rw-r--r-- | Install/MCServer_medium_detail_debug.cmd | 2 | ||||
-rw-r--r-- | SetFlags.cmake | 12 | ||||
-rw-r--r-- | src/Globals.h | 1 | ||||
-rw-r--r-- | src/OSSupport/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/OSSupport/Event.cpp | 4 | ||||
-rw-r--r-- | src/OSSupport/Semaphore.cpp | 107 | ||||
-rw-r--r-- | src/OSSupport/Semaphore.h | 17 | ||||
-rw-r--r-- | src/main.cpp | 171 |
11 files changed, 106 insertions, 232 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ae83662c9..e3af054ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ cmake_minimum_required (VERSION 2.8.7) # Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html ) enable_language(CXX C) +# Enable the support for solution folders in MSVC +if (MSVC) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + # These env variables are used for configuring Travis CI builds. # See https://github.com/mc-server/MCServer/pull/767 if(DEFINED ENV{TRAVIS_MCSERVER_BUILD_TYPE}) @@ -67,6 +72,7 @@ if(${BUILD_UNSTABLE_TOOLS}) add_subdirectory(Tools/GeneratorPerformanceTest/) endif() +include(CheckCXXCompilerFlag) include(SetFlags.cmake) set_flags() set_lib_flags() @@ -130,7 +136,7 @@ add_subdirectory(lib/sqlite/) add_subdirectory(lib/SQLiteCpp/) add_subdirectory(lib/expat/) add_subdirectory(lib/luaexpat/) -add_subdirectory(lib/libevent/) +add_subdirectory(lib/libevent/ EXCLUDE_FROM_ALL) # Add proper include directories so that SQLiteCpp can find SQLite3: get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES) @@ -160,3 +166,13 @@ if(${SELF_TEST}) add_subdirectory (tests) endif() +# Put project into solution folders in MSVC: +if (MSVC) + set_target_properties(event_core event_extra expat jsoncpp lua luaexpat mbedtls sqlite SQLiteCpp tolualib zlib PROPERTIES FOLDER Lib) + set_target_properties(luaproxy tolua PROPERTIES FOLDER Support) + if (${SELF_TEST}) + set_target_properties(Network PROPERTIES FOLDER Lib) + set_target_properties(arraystocoords-exe coordinates-exe copies-exe copyblocks-exe creatable-exe EchoServer Google-exe ChunkBuffer NameLookup PROPERTIES FOLDER Tests) + endif() +endif() + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e57e6efb..1b43ed214 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ Here are the conventions: - This helps prevent mistakes such as `if (a & 1 == 0)` * * Use the provided wrappers for OS stuff: - - Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep` + - Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep` * No magic numbers, use named constants: - `E_ITEM_XXX`, `E_BLOCK_XXX` and `E_META_XXX` for items and blocks - `cEntity::etXXX` for entity types, `cMonster::mtXXX` for mob types diff --git a/Install/MCServer_high_detail_debug.cmd b/Install/MCServer_high_detail_debug.cmd index 384189c42..d94af8150 100644 --- a/Install/MCServer_high_detail_debug.cmd +++ b/Install/MCServer_high_detail_debug.cmd @@ -1 +1 @@ -MCServer /cdf
\ No newline at end of file +MCServer --crash-dump-full diff --git a/Install/MCServer_medium_detail_debug.cmd b/Install/MCServer_medium_detail_debug.cmd index b5bb0954c..0a33c27fd 100644 --- a/Install/MCServer_medium_detail_debug.cmd +++ b/Install/MCServer_medium_detail_debug.cmd @@ -1 +1 @@ -MCServer /cdg
\ No newline at end of file +MCServer --crash-dump-globals diff --git a/SetFlags.cmake b/SetFlags.cmake index b79551eef..57cab5a1c 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -63,7 +63,7 @@ macro(set_flags) set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") elseif(APPLE) - + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) @@ -262,8 +262,11 @@ macro(set_exe_flags) add_flags_cxx("-Wno-documentation") endif() if ("${CLANG_VERSION}" VERSION_GREATER 3.5) - # Use this flag to ignore error for a reserved macro problem in sqlite 3 - add_flags_cxx("-Wno-reserved-id-macro") + check_cxx_compiler_flag(-Wno-reserved-id-macro HAS_NO_RESERVED_ID_MACRO) + if (HAS_NO_RESERVED_ID_MACRO) + # Use this flag to ignore error for a reserved macro problem in sqlite 3 + add_flags_cxx("-Wno-reserved-id-macro") + endif() endif() endif() endif() @@ -277,7 +280,7 @@ endmacro() # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=missing-prototypes -Wno-error=deprecated") # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=shadow -Wno-error=old-style-cast -Wno-error=switch-enum -Wno-error=switch") # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=float-equal -Wno-error=global-constructors") - + # if ("${CLANG_VERSION}" VERSION_GREATER 3.0) # # flags that are not present in 3.0 # set_source_files_properties(${FILENAME} PROPERTIES COMPILE_FLAGS "-Wno-error=covered-switch-default ") @@ -286,4 +289,3 @@ endmacro() # endif() # endforeach() # endif() - diff --git a/src/Globals.h b/src/Globals.h index 27d944fcc..e7b7fdcac 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -265,7 +265,6 @@ template class SizeChecker<UInt8, 1>; // Common headers (part 1, without macros): #include "StringUtils.h" #include "OSSupport/CriticalSection.h" - #include "OSSupport/Semaphore.h" #include "OSSupport/Event.h" #include "OSSupport/File.h" #include "Logger.h" diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index d1db0373d..df47394ae 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -15,7 +15,6 @@ SET (SRCS IsThread.cpp NetworkInterfaceEnum.cpp NetworkSingleton.cpp - Semaphore.cpp ServerHandleImpl.cpp StackTrace.cpp TCPLinkImpl.cpp @@ -34,7 +33,6 @@ SET (HDRS Network.h NetworkSingleton.h Queue.h - Semaphore.h ServerHandleImpl.h StackTrace.h TCPLinkImpl.h diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp index 760e536a1..38144ead3 100644 --- a/src/OSSupport/Event.cpp +++ b/src/OSSupport/Event.cpp @@ -1,8 +1,8 @@ // Event.cpp -// Implements the cEvent object representing an OS-specific synchronization primitive that can be waited-for -// Implemented as an Event on Win and as a 1-semaphore on *nix +// Interfaces to the cEvent object representing a synchronization primitive that can be waited-for +// Implemented using C++11 condition variable and mutex #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules diff --git a/src/OSSupport/Semaphore.cpp b/src/OSSupport/Semaphore.cpp deleted file mode 100644 index 6a2d57901..000000000 --- a/src/OSSupport/Semaphore.cpp +++ /dev/null @@ -1,107 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - - - - - -cSemaphore::cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount /* = 0 */) -#ifndef _WIN32 - : m_bNamed( false) -#endif -{ -#ifndef _WIN32 - (void)a_MaxCount; - m_Handle = new sem_t; - if (sem_init( (sem_t*)m_Handle, 0, 0)) - { - LOG("WARNING cSemaphore: Could not create unnamed semaphore, fallback to named."); - delete (sem_t*)m_Handle; // named semaphores return their own address - m_bNamed = true; - - AString Name; - Printf(Name, "cSemaphore%p", this); - m_Handle = sem_open(Name.c_str(), O_CREAT, 777, a_InitialCount); - if (m_Handle == SEM_FAILED) - { - LOG("ERROR: Could not create Semaphore. (%i)", errno); - } - else - { - if (sem_unlink(Name.c_str()) != 0) - { - LOG("ERROR: Could not unlink cSemaphore. (%i)", errno); - } - } - } -#else - m_Handle = CreateSemaphore( - nullptr, // security attribute - a_InitialCount, // initial count - a_MaxCount, // maximum count - 0 // name (optional) - ); -#endif -} - - - - - -cSemaphore::~cSemaphore() -{ -#ifdef _WIN32 - CloseHandle( m_Handle); -#else - if (m_bNamed) - { - if (sem_close( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not close cSemaphore. (%i)", errno); - } - } - else - { - sem_destroy( (sem_t*)m_Handle); - delete (sem_t*)m_Handle; - } - m_Handle = 0; - -#endif -} - - - - - -void cSemaphore::Wait() -{ -#ifndef _WIN32 - if (sem_wait( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not wait for cSemaphore. (%i)", errno); - } -#else - WaitForSingleObject( m_Handle, INFINITE); -#endif -} - - - - - -void cSemaphore::Signal() -{ -#ifndef _WIN32 - if (sem_post( (sem_t*)m_Handle) != 0) - { - LOG("ERROR: Could not signal cSemaphore. (%i)", errno); - } -#else - ReleaseSemaphore( m_Handle, 1, nullptr); -#endif -} - - - - diff --git a/src/OSSupport/Semaphore.h b/src/OSSupport/Semaphore.h deleted file mode 100644 index 57fa4bdb2..000000000 --- a/src/OSSupport/Semaphore.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -class cSemaphore -{ -public: - cSemaphore( unsigned int a_MaxCount, unsigned int a_InitialCount = 0); - ~cSemaphore(); - - void Wait(); - void Signal(); -private: - void * m_Handle; // HANDLE pointer - -#ifndef _WIN32 - bool m_bNamed; -#endif -}; diff --git a/src/main.cpp b/src/main.cpp index d5c39cecd..152339e12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,7 +39,7 @@ bool cRoot::m_RunAsService = false; #if defined(_WIN32) - SERVICE_STATUS_HANDLE g_StatusHandle = NULL; + SERVICE_STATUS_HANDLE g_StatusHandle = nullptr; HANDLE g_ServiceThread = INVALID_HANDLE_VALUE; #define SERVICE_NAME "MCServerService" #endif @@ -145,7 +145,7 @@ Its purpose is to create the crashdump using the dbghlp DLLs */ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo) { - char * newStack = &g_ExceptionStack[sizeof(g_ExceptionStack)]; + char * newStack = &g_ExceptionStack[sizeof(g_ExceptionStack) - 1]; char * oldStack; // Use the substitute stack: @@ -249,6 +249,7 @@ void universalMain(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo) + #if defined(_WIN32) //////////////////////////////////////////////////////////////////////////////// // serviceWorkerThread: Keep the service alive @@ -266,6 +267,7 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam) + //////////////////////////////////////////////////////////////////////////////// // serviceSetState: Set the internal status of the service @@ -319,14 +321,10 @@ void WINAPI serviceCtrlHandler(DWORD CtrlCode) void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) { - #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP) - Sleep(10000); - #endif - char applicationFilename[MAX_PATH]; char applicationDirectory[MAX_PATH]; - GetModuleFileName(NULL, applicationFilename, sizeof(applicationFilename)); // This binary's file path. + GetModuleFileName(nullptr, applicationFilename, sizeof(applicationFilename)); // This binary's file path. // Strip off the filename, keep only the path: strncpy_s(applicationDirectory, sizeof(applicationDirectory), applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename)); @@ -337,8 +335,7 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) SetCurrentDirectory(applicationDirectory); g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler); - - if (g_StatusHandle == NULL) + if (g_StatusHandle == nullptr) { OutputDebugStringA("RegisterServiceCtrlHandler() failed\n"); serviceSetState(0, SERVICE_STOPPED, GetLastError()); @@ -347,8 +344,9 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0); - g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL); - if (g_ServiceThread == NULL) + DWORD ThreadID; + g_ServiceThread = CreateThread(nullptr, 0, serviceWorkerThread, nullptr, 0, &ThreadID); + if (g_ServiceThread == nullptr) { OutputDebugStringA("CreateThread() failed\n"); serviceSetState(0, SERVICE_STOPPED, GetLastError()); @@ -364,50 +362,39 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) + + std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) { try { + // Parse the comand line args: TCLAP::CmdLine cmd("MCServer"); - - TCLAP::ValueArg<int> slotsArg("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); - - TCLAP::MultiArg<int> portsArg("p", "port", "The port number the server should listen to", false, "port", cmd); - - TCLAP::SwitchArg commLogArg("", "log-comm", "Log server client communications to file", cmd); - - TCLAP::SwitchArg commLogInArg("", "log-comm-in", "Log inbound server client communications to file", cmd); - - TCLAP::SwitchArg commLogOutArg("", "log-comm-out", "Log outbound server client communications to file", cmd); - - TCLAP::SwitchArg noBufArg("", "no-output-buffering", "Disable output buffering", cmd); - - TCLAP::SwitchArg runAsServiceArg("d", "run-as-service", "Run as a service on Windows", cmd); - - cmd.ignoreUnmatched(true); - + TCLAP::ValueArg<int> slotsArg ("s", "max-players", "Maximum number of slots for the server to use, overrides setting in setting.ini", false, -1, "number", cmd); + TCLAP::MultiArg<int> portsArg ("p", "port", "The port number the server should listen to", false, "port", cmd); + TCLAP::SwitchArg commLogArg ("", "log-comm", "Log server client communications to file", cmd); + TCLAP::SwitchArg commLogInArg ("", "log-comm-in", "Log inbound server client communications to file", cmd); + TCLAP::SwitchArg commLogOutArg ("", "log-comm-out", "Log outbound server client communications to file", cmd); + TCLAP::SwitchArg crashDumpFull ("", "crash-dump-full", "Crashdumps created by the server will contain full server memory", cmd); + TCLAP::SwitchArg crashDumpGlobals("", "crash-dump-globals", "Crashdumps created by the server will contain the global variables' values", cmd); + TCLAP::SwitchArg noBufArg ("", "no-output-buffering", "Disable output buffering", cmd); + TCLAP::SwitchArg runAsServiceArg ("d", "run-as-service", "Run as a service on Windows", cmd); cmd.parse(argc, argv); + // Copy the parsed args' values into a settings repository: auto repo = cpp14::make_unique<cMemorySettingsRepository>(); - if (slotsArg.isSet()) { - int slots = slotsArg.getValue(); - repo->AddValue("Server", "MaxPlayers", static_cast<Int64>(slots)); - } - if (portsArg.isSet()) { - std::vector<int> ports = portsArg.getValue(); - for (auto port : ports) + for (auto port: portsArg.getValue()) { repo->AddValue("Server", "Port", static_cast<Int64>(port)); } } - if (commLogArg.getValue()) { g_ShouldLogCommIn = true; @@ -418,115 +405,111 @@ std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) g_ShouldLogCommIn = commLogInArg.getValue(); g_ShouldLogCommOut = commLogOutArg.getValue(); } - if (noBufArg.getValue()) { setvbuf(stdout, nullptr, _IONBF, 0); } + repo->SetReadOnly(); + // Set the service flag directly to cRoot: if (runAsServiceArg.getValue()) { cRoot::m_RunAsService = true; } - repo->SetReadOnly(); + // Apply the CrashDump flags for platforms that support them: + #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC + if (crashDumpGlobals.getValue()) + { + g_DumpFlags = static_cast<MINIDUMP_TYPE>(g_DumpFlags | MiniDumpWithDataSegs); + } + if (crashDumpFull.getValue()) + { + g_DumpFlags = static_cast<MINIDUMP_TYPE>(g_DumpFlags | MiniDumpWithFullMemory); + } + #endif // 32-bit Windows app compiled in MSVC return repo; } - catch (TCLAP::ArgException &e) + catch (const TCLAP::ArgException & exc) { - printf("error reading command line %s for arg %s", e.error().c_str(), e.argId().c_str()); + printf("Error reading command line %s for arg %s", exc.error().c_str(), exc.argId().c_str()); return cpp14::make_unique<cMemorySettingsRepository>(); } } + + + //////////////////////////////////////////////////////////////////////////////// // main: int main(int argc, char **argv) { - #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - InitLeakFinder(); + InitLeakFinder(); #endif // Magic code to produce dump-files on Windows if the server crashes: - #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) - HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL"); - g_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if (g_WriteMiniDump != nullptr) - { - _snprintf_s(g_DumpFileName, ARRAYCOUNT(g_DumpFileName), _TRUNCATE, "crash_mcs_%x.dmp", GetCurrentProcessId()); - SetUnhandledExceptionFilter(LastChanceExceptionFilter); - - // Parse arguments for minidump flags: - for (int i = 0; i < argc; i++) + #if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC + HINSTANCE hDbgHelp = LoadLibrary("DBGHELP.DLL"); + g_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); + if (g_WriteMiniDump != nullptr) { - if (_stricmp(argv[i], "/cdg") == 0) - { - // Add globals to the dump - g_DumpFlags = (MINIDUMP_TYPE)(g_DumpFlags | MiniDumpWithDataSegs); - } - else if (_stricmp(argv[i], "/cdf") == 0) - { - // Add full memory to the dump (HUUUGE file) - g_DumpFlags = (MINIDUMP_TYPE)(g_DumpFlags | MiniDumpWithFullMemory); - } - } // for i - argv[] - } - #endif // _WIN32 && !_WIN64 + _snprintf_s(g_DumpFileName, ARRAYCOUNT(g_DumpFileName), _TRUNCATE, "crash_mcs_%x.dmp", GetCurrentProcessId()); + SetUnhandledExceptionFilter(LastChanceExceptionFilter); + } + #endif // 32-bit Windows app compiled in MSVC // End of dump-file magic + #if defined(_DEBUG) && defined(_MSC_VER) - _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - // _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output) - // Only useful when the leak is in the same sequence all the time - // _CrtSetBreakAlloc(85950); + // _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output) + // Only useful when the leak is in the same sequence all the time + // _CrtSetBreakAlloc(85950); #endif // _DEBUG && _MSC_VER #ifndef _DEBUG - std::signal(SIGSEGV, NonCtrlHandler); - std::signal(SIGTERM, NonCtrlHandler); - std::signal(SIGINT, NonCtrlHandler); - std::signal(SIGABRT, NonCtrlHandler); - #ifdef SIGABRT_COMPAT - std::signal(SIGABRT_COMPAT, NonCtrlHandler); - #endif // SIGABRT_COMPAT + std::signal(SIGSEGV, NonCtrlHandler); + std::signal(SIGTERM, NonCtrlHandler); + std::signal(SIGINT, NonCtrlHandler); + std::signal(SIGABRT, NonCtrlHandler); + #ifdef SIGABRT_COMPAT + std::signal(SIGABRT_COMPAT, NonCtrlHandler); + #endif // SIGABRT_COMPAT #endif - // DEBUG: test the dumpfile creation: - // *((int *)0) = 0; - auto argsRepo = parseArguments(argc, argv); #if defined(_WIN32) - // Attempt to run as a service - if (cRoot::m_RunAsService) - { - SERVICE_TABLE_ENTRY ServiceTable[] = + // Attempt to run as a service + if (cRoot::m_RunAsService) { - { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, - { NULL, NULL } - }; + SERVICE_TABLE_ENTRY ServiceTable[] = + { + { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, + { nullptr, nullptr } + }; - if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) - { - LOGERROR("Attempted, but failed, service startup."); - return GetLastError(); + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) + { + LOGERROR("Attempted, but failed, service startup."); + return GetLastError(); + } } - } - else + else #endif { - // Not running as a service, do normal startup + // Not running as a Windows service, do normal startup universalMain(std::move(argsRepo)); } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - DeinitLeakFinder(); + DeinitLeakFinder(); #endif return EXIT_SUCCESS; |