Split managed application status and IApplication status (#1148)

Split managed application status and IApplication status
This commit is contained in:
Pavel Krymets 2018-08-06 09:41:56 -07:00 committed by GitHub
parent 3f6288e141
commit c2f5101b73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 86 additions and 97 deletions

View File

@ -13,7 +13,6 @@ public:
: m_HR(hr), : m_HR(hr),
PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenAdded) PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenAdded)
{ {
m_status = APPLICATION_STATUS::RUNNING;
} }
~ServerErrorApplication() = default; ~ServerErrorApplication() = default;

View File

@ -54,7 +54,7 @@ APPLICATION_INFO::GetOrCreateApplication(
) )
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
SRWExclusiveLock lock(m_applicationLock); SRWExclusiveLock lock(m_applicationLock);
auto& httpApplication = *pHttpContext->GetApplication(); auto& httpApplication = *pHttpContext->GetApplication();
@ -72,7 +72,7 @@ APPLICATION_INFO::GetOrCreateApplication(
else else
{ {
// another thread created the application // another thread created the application
FINISHED(S_OK); FINISHED(S_OK);
} }
} }
@ -124,7 +124,7 @@ Finished:
if (m_pApplication) if (m_pApplication)
{ {
pApplication = ReferenceApplication(m_pApplication.get()); pApplication = ReferenceApplication(m_pApplication.get());
} }
return hr; return hr;
@ -410,7 +410,7 @@ APPLICATION_INFO::RecycleApplication()
} }
DWORD WINAPI DWORD WINAPI
APPLICATION_INFO::DoRecycleApplication( APPLICATION_INFO::DoRecycleApplication(
LPVOID lpParam) LPVOID lpParam)
{ {

View File

@ -95,20 +95,12 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
// the error should already been logged to window event log for the first request // the error should already been logged to window event log for the first request
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE); FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
} }
DBG_ASSERT(pHttpContext); DBG_ASSERT(pHttpContext);
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication; std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;
FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(pHttpContext, pApplication)); FINISHED_IF_FAILED(m_pApplicationInfo->GetOrCreateApplication(pHttpContext, pApplication));
// We allow RECYCLED application to serve pages
if (pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
pApplication->QueryStatus() != APPLICATION_STATUS::STARTING &&
pApplication->QueryStatus() != APPLICATION_STATUS::RECYCLED)
{
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED));
}
IREQUEST_HANDLER* pHandler; IREQUEST_HANDLER* pHandler;
// Create RequestHandler and process the request // Create RequestHandler and process the request
FINISHED_IF_FAILED(pApplication->CreateHandler(pHttpContext, &pHandler)); FINISHED_IF_FAILED(pApplication->CreateHandler(pHttpContext, &pHandler));

View File

@ -13,6 +13,7 @@ public:
AppOfflineApplication(IHttpApplication& pApplication) AppOfflineApplication(IHttpApplication& pApplication)
: PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenRemoved) : PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenRemoved)
{ {
CheckAppOffline();
} }
HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler) override; HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler) override;

View File

@ -9,11 +9,12 @@
APPLICATION_STATUS PollingAppOfflineApplication::QueryStatus() APPLICATION_STATUS PollingAppOfflineApplication::QueryStatus()
{ {
return (AppOfflineExists() == (m_mode == StopWhenRemoved)) ? APPLICATION_STATUS::RUNNING : APPLICATION_STATUS::RECYCLED; CheckAppOffline();
return APPLICATION::QueryStatus();
} }
bool void
PollingAppOfflineApplication::AppOfflineExists() PollingAppOfflineApplication::CheckAppOffline()
{ {
const auto ulCurrentTime = GetTickCount64(); const auto ulCurrentTime = GetTickCount64();
// //
@ -29,12 +30,16 @@ PollingAppOfflineApplication::AppOfflineExists()
m_fAppOfflineFound = is_regular_file(m_appOfflineLocation); m_fAppOfflineFound = is_regular_file(m_appOfflineLocation);
if(m_fAppOfflineFound) if(m_fAppOfflineFound)
{ {
LOG_IF_FAILED(OnAppOfflineFound()); LOG_IF_FAILED(OnAppOfflineFound());
} }
m_ulLastCheckTime = ulCurrentTime; m_ulLastCheckTime = ulCurrentTime;
} }
} }
return m_fAppOfflineFound;
if (m_fAppOfflineFound != (m_mode == StopWhenRemoved))
{
Stop(/* fServerInitiated */ false);
}
} }

View File

@ -25,9 +25,9 @@ public:
} }
APPLICATION_STATUS QueryStatus() override; APPLICATION_STATUS QueryStatus() override;
bool AppOfflineExists(); void CheckAppOffline();
virtual HRESULT OnAppOfflineFound() = 0; virtual HRESULT OnAppOfflineFound() = 0;
void Stop(bool fServerInitiated) override { UNREFERENCED_PARAMETER(fServerInitiated); } void StopInternal(bool fServerInitiated) override { UNREFERENCED_PARAMETER(fServerInitiated); }
protected: protected:
std::experimental::filesystem::path m_appOfflineLocation; std::experimental::filesystem::path m_appOfflineLocation;
@ -36,7 +36,7 @@ protected:
private: private:
static const int c_appOfflineRefreshIntervalMS = 200; static const int c_appOfflineRefreshIntervalMS = 200;
std::string m_strAppOfflineContent; std::string m_strAppOfflineContent;
ULONGLONG m_ulLastCheckTime; ULONGLONG m_ulLastCheckTime;
bool m_fAppOfflineFound; bool m_fAppOfflineFound;
SRWLOCK m_statusLock {}; SRWLOCK m_statusLock {};
PollingAppOfflineApplicationMode m_mode; PollingAppOfflineApplicationMode m_mode;

View File

@ -7,11 +7,10 @@
#include "exceptions.h" #include "exceptions.h"
#include "utility.h" #include "utility.h"
#include "ntassert.h" #include "ntassert.h"
#include "SRWExclusiveLock.h"
class APPLICATION : public IAPPLICATION class APPLICATION : public IAPPLICATION
{ {
public: public:
// Non-copyable // Non-copyable
APPLICATION(const APPLICATION&) = delete; APPLICATION(const APPLICATION&) = delete;
@ -20,24 +19,38 @@ public:
APPLICATION_STATUS APPLICATION_STATUS
QueryStatus() override QueryStatus() override
{ {
return m_status; return m_fStopCalled ? APPLICATION_STATUS::RECYCLED : APPLICATION_STATUS::RUNNING;
} }
APPLICATION() APPLICATION()
: m_cRefs(1) : m_fStopCalled(false),
m_cRefs(1)
{ {
InitializeSRWLock(&m_stateLock); InitializeSRWLock(&m_stateLock);
} }
VOID VOID
Stop(bool fServerInitiated) override Stop(bool fServerInitiated) override
{ {
UNREFERENCED_PARAMETER(fServerInitiated); SRWExclusiveLock stopLock(m_stateLock);
if (m_fStopCalled)
{
return;
}
m_fStopCalled = true; m_fStopCalled = true;
StopInternal(fServerInitiated);
}
virtual
VOID
StopInternal(bool fServerInitiated)
{
UNREFERENCED_PARAMETER(fServerInitiated);
} }
VOID VOID
ReferenceApplication() override ReferenceApplication() override
@ -59,11 +72,9 @@ public:
} }
protected: protected:
volatile APPLICATION_STATUS m_status = APPLICATION_STATUS::UNKNOWN;
SRWLOCK m_stateLock; SRWLOCK m_stateLock;
bool m_fStopCalled; bool m_fStopCalled;
private: private:
mutable LONG m_cRefs;
mutable LONG m_cRefs;
}; };

View File

@ -8,12 +8,8 @@
enum APPLICATION_STATUS enum APPLICATION_STATUS
{ {
UNKNOWN = 0,
STARTING,
RUNNING, RUNNING,
SHUTDOWN,
RECYCLED, RECYCLED,
FAIL
}; };
struct APPLICATION_PARAMETER struct APPLICATION_PARAMETER

View File

@ -15,9 +15,9 @@ InProcessApplicationBase::InProcessApplicationBase(
} }
VOID VOID
InProcessApplicationBase::Stop(bool fServerInitiated) InProcessApplicationBase::StopInternal(bool fServerInitiated)
{ {
AppOfflineTrackingApplication::Stop(fServerInitiated); AppOfflineTrackingApplication::StopInternal(fServerInitiated);
// Stop was initiated by server no need to do anything, server would stop on it's own // Stop was initiated by server no need to do anything, server would stop on it's own
if (fServerInitiated) if (fServerInitiated)

View File

@ -18,7 +18,7 @@ public:
~InProcessApplicationBase() = default; ~InProcessApplicationBase() = default;
VOID Stop(bool fServerInitiated) override; VOID StopInternal(bool fServerInitiated) override;
protected: protected:
BOOL m_fRecycleCalled; BOOL m_fRecycleCalled;

View File

@ -32,7 +32,6 @@ public:
ShuttingDownApplication(IHttpServer& pHttpServer, IHttpApplication& pHttpApplication) ShuttingDownApplication(IHttpServer& pHttpServer, IHttpApplication& pHttpApplication)
: InProcessApplicationBase(pHttpServer, pHttpApplication) : InProcessApplicationBase(pHttpServer, pHttpApplication)
{ {
m_status = APPLICATION_STATUS::RUNNING;
} }
~ShuttingDownApplication() = default; ~ShuttingDownApplication() = default;

View File

@ -16,7 +16,6 @@ public:
: m_disableLogs(disableLogs), : m_disableLogs(disableLogs),
InProcessApplicationBase(pServer, pApplication) InProcessApplicationBase(pServer, pApplication)
{ {
m_status = APPLICATION_STATUS::RUNNING;
html500Page = std::string("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \ html500Page = std::string("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \ <html xmlns=\"http://www.w3.org/1999/xhtml\"> \
<head> \ <head> \

View File

@ -23,7 +23,6 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
APPLICATION_PARAMETER *pParameters, APPLICATION_PARAMETER *pParameters,
DWORD nParameters) : DWORD nParameters) :
InProcessApplicationBase(pHttpServer, pApplication), InProcessApplicationBase(pHttpServer, pApplication),
m_pHttpServer(pHttpServer),
m_ProcessExitCode(0), m_ProcessExitCode(0),
m_fBlockCallbacksIntoManaged(FALSE), m_fBlockCallbacksIntoManaged(FALSE),
m_fShutdownCalledFromNative(FALSE), m_fShutdownCalledFromNative(FALSE),
@ -40,7 +39,7 @@ IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
} }
} }
m_status = APPLICATION_STATUS::STARTING; m_status = MANAGED_APPLICATION_STATUS::STARTING;
} }
IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION() IN_PROCESS_APPLICATION::~IN_PROCESS_APPLICATION()
@ -63,22 +62,13 @@ IN_PROCESS_APPLICATION::DoShutDown(
__override __override
VOID VOID
IN_PROCESS_APPLICATION::Stop(bool fServerInitiated) IN_PROCESS_APPLICATION::StopInternal(bool fServerInitiated)
{ {
UNREFERENCED_PARAMETER(fServerInitiated); UNREFERENCED_PARAMETER(fServerInitiated);
HRESULT hr = S_OK; HRESULT hr = S_OK;
CHandle hThread; CHandle hThread;
DWORD dwThreadStatus = 0; DWORD dwThreadStatus = 0;
SRWExclusiveLock stopLock(m_stateLock);
if (m_fStopCalled)
{
return;
}
AppOfflineTrackingApplication::Stop(fServerInitiated);
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS(); DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
if (IsDebuggerPresent()) if (IsDebuggerPresent())
@ -137,7 +127,7 @@ Finished:
m_pConfig->QueryConfigPath()->QueryStr()); m_pConfig->QueryConfigPath()->QueryStr());
} }
InProcessApplicationBase::Stop(fServerInitiated); InProcessApplicationBase::StopInternal(fServerInitiated);
} }
VOID VOID
@ -152,16 +142,16 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
} }
if (m_fShutdownCalledFromNative || if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING || m_status == MANAGED_APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL) m_status == MANAGED_APPLICATION_STATUS::FAIL)
{ {
return; return;
} }
{ {
if (m_fShutdownCalledFromNative || if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING || m_status == MANAGED_APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL) m_status == MANAGED_APPLICATION_STATUS::FAIL)
{ {
return; return;
} }
@ -171,7 +161,7 @@ IN_PROCESS_APPLICATION::ShutDownInternal()
// managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative // managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
// is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler. // is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
m_fShutdownCalledFromNative = TRUE; m_fShutdownCalledFromNative = TRUE;
m_status = APPLICATION_STATUS::RECYCLED; m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
if (!m_fShutdownCalledFromManaged) if (!m_fShutdownCalledFromManaged)
{ {
@ -249,18 +239,18 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
HRESULT hr = S_OK; HRESULT hr = S_OK;
DWORD dwTimeout; DWORD dwTimeout;
DWORD dwResult; DWORD dwResult;
ReferenceApplication(); ReferenceApplication();
if (m_status != APPLICATION_STATUS::STARTING) if (m_status != MANAGED_APPLICATION_STATUS::STARTING)
{ {
// Core CLR has already been loaded. // Core CLR has already been loaded.
// Cannot load more than once even there was a failure // Cannot load more than once even there was a failure
if (m_status == APPLICATION_STATUS::FAIL) if (m_status == MANAGED_APPLICATION_STATUS::FAIL)
{ {
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE; hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
} }
else if (m_status == APPLICATION_STATUS::SHUTDOWN) else if (m_status == MANAGED_APPLICATION_STATUS::SHUTDOWN)
{ {
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED); hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
} }
@ -289,13 +279,13 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
LOG_IF_FAILED(m_pLoggerProvider->Start()); LOG_IF_FAILED(m_pLoggerProvider->Start());
} }
if (m_status != APPLICATION_STATUS::STARTING) if (m_status != MANAGED_APPLICATION_STATUS::STARTING)
{ {
if (m_status == APPLICATION_STATUS::FAIL) if (m_status == MANAGED_APPLICATION_STATUS::FAIL)
{ {
hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE; hr = E_APPLICATION_ACTIVATION_EXEC_FAILURE;
} }
else if (m_status == APPLICATION_STATUS::SHUTDOWN) else if (m_status == MANAGED_APPLICATION_STATUS::SHUTDOWN)
{ {
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED); hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IS_SCHEDULED);
} }
@ -363,13 +353,13 @@ IN_PROCESS_APPLICATION::LoadManagedApplication
goto Finished; goto Finished;
} }
m_status = APPLICATION_STATUS::RUNNING; m_status = MANAGED_APPLICATION_STATUS::RUNNING_MANAGED;
} }
Finished: Finished:
if (FAILED(hr)) if (FAILED(hr))
{ {
m_status = APPLICATION_STATUS::FAIL; m_status = MANAGED_APPLICATION_STATUS::FAIL;
UTILITY::LogEventF(g_hEventLog, UTILITY::LogEventF(g_hEventLog,
EVENTLOG_ERROR_TYPE, EVENTLOG_ERROR_TYPE,
@ -444,7 +434,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
hostfxr_main_fn pProc; hostfxr_main_fn pProc;
std::unique_ptr<HOSTFXR_OPTIONS> hostFxrOptions = NULL; std::unique_ptr<HOSTFXR_OPTIONS> hostFxrOptions = NULL;
DBG_ASSERT(m_status == APPLICATION_STATUS::STARTING); DBG_ASSERT(m_status == MANAGED_APPLICATION_STATUS::STARTING);
pProc = s_fMainCallback; pProc = s_fMainCallback;
if (pProc == nullptr) if (pProc == nullptr)
@ -502,7 +492,7 @@ Finished:
// Don't bother locking here as there will always be a race between receiving a native shutdown // Don't bother locking here as there will always be a race between receiving a native shutdown
// notification and unexpected managed exit. // notification and unexpected managed exit.
// //
m_status = APPLICATION_STATUS::SHUTDOWN; m_status = MANAGED_APPLICATION_STATUS::SHUTDOWN;
m_fShutdownCalledFromManaged = TRUE; m_fShutdownCalledFromManaged = TRUE;
FreeLibrary(hModule); FreeLibrary(hModule);
m_pLoggerProvider->Stop(); m_pLoggerProvider->Stop();
@ -575,12 +565,12 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
{ {
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
} }
LOG_INFOF("Managed application exited with code %d", m_ProcessExitCode); LOG_INFOF("Managed application exited with code %d", m_ProcessExitCode);
} }
__except(GetExceptionCode() != 0) __except(GetExceptionCode() != 0)
{ {
LOG_INFOF("Managed threw an exception %d", GetExceptionCode()); LOG_INFOF("Managed threw an exception %d", GetExceptionCode());
hr = HRESULT_FROM_WIN32(GetLastError()); hr = HRESULT_FROM_WIN32(GetLastError());
} }

View File

@ -26,7 +26,7 @@ public:
__override __override
VOID VOID
Stop(bool fServerInitiated) override; StopInternal(bool fServerInitiated) override;
VOID VOID
SetCallbackHandles( SetCallbackHandles(
@ -111,7 +111,14 @@ public:
private: private:
IHttpServer & m_pHttpServer; enum MANAGED_APPLICATION_STATUS
{
UNKNOWN = 0,
STARTING,
RUNNING_MANAGED,
SHUTDOWN,
FAIL
};
// Thread executing the .NET Core process // Thread executing the .NET Core process
HANDLE m_hThread; HANDLE m_hThread;
@ -138,6 +145,7 @@ private:
volatile BOOL m_fShutdownCalledFromNative; volatile BOOL m_fShutdownCalledFromNative;
volatile BOOL m_fShutdownCalledFromManaged; volatile BOOL m_fShutdownCalledFromManaged;
BOOL m_fInitialized; BOOL m_fInitialized;
MANAGED_APPLICATION_STATUS m_status;
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig; std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
static IN_PROCESS_APPLICATION* s_Application; static IN_PROCESS_APPLICATION* s_Application;

View File

@ -12,7 +12,6 @@ OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
m_fWebSocketSupported(WEBSOCKET_STATUS::WEBSOCKET_UNKNOWN), m_fWebSocketSupported(WEBSOCKET_STATUS::WEBSOCKET_UNKNOWN),
m_pConfig(std::move(pConfig)) m_pConfig(std::move(pConfig))
{ {
m_status = APPLICATION_STATUS::RUNNING;
m_pProcessManager = NULL; m_pProcessManager = NULL;
} }
@ -62,16 +61,9 @@ OUT_OF_PROCESS_APPLICATION::GetProcess(
__override __override
VOID VOID
OUT_OF_PROCESS_APPLICATION::Stop(bool fServerInitiated) OUT_OF_PROCESS_APPLICATION::StopInternal(bool fServerInitiated)
{ {
SRWExclusiveLock lock(m_stateLock); AppOfflineTrackingApplication::StopInternal(fServerInitiated);
if (m_fStopCalled)
{
return;
}
AppOfflineTrackingApplication::Stop(fServerInitiated);
if (m_pProcessManager != NULL) if (m_pProcessManager != NULL)
{ {

View File

@ -32,7 +32,7 @@ public:
__override __override
VOID VOID
Stop(bool fServerInitiated) StopInternal(bool fServerInitiated)
override; override;
__override __override

View File

@ -6,8 +6,6 @@
#include "EventLog.h" #include "EventLog.h"
#include "exceptions.h" #include "exceptions.h"
extern HANDLE g_hEventLog;
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline() HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
{ {
LOG_INFOF("Starting app_offline monitoring in application %S", m_applicationPath.c_str()); LOG_INFOF("Starting app_offline monitoring in application %S", m_applicationPath.c_str());
@ -26,11 +24,9 @@ HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
return hr; return hr;
} }
void AppOfflineTrackingApplication::Stop(bool fServerInitiated) void AppOfflineTrackingApplication::StopInternal(bool fServerInitiated)
{ {
APPLICATION::Stop(fServerInitiated); APPLICATION::StopInternal(fServerInitiated);
m_status = APPLICATION_STATUS::RECYCLED;
if (m_fileWatcher) if (m_fileWatcher)
{ {

View File

@ -12,7 +12,8 @@ class AppOfflineTrackingApplication: public APPLICATION
{ {
public: public:
AppOfflineTrackingApplication(const IHttpApplication& application) AppOfflineTrackingApplication(const IHttpApplication& application)
: m_applicationPath(application.GetApplicationPhysicalPath()), : APPLICATION(),
m_applicationPath(application.GetApplicationPhysicalPath()),
m_fileWatcher(nullptr), m_fileWatcher(nullptr),
m_fAppOfflineProcessed(false) m_fAppOfflineProcessed(false)
{ {
@ -23,15 +24,15 @@ public:
if (m_fileWatcher) if (m_fileWatcher)
{ {
m_fileWatcher->StopMonitor(); m_fileWatcher->StopMonitor();
} }
}; };
HRESULT HRESULT
StartMonitoringAppOffline(); StartMonitoringAppOffline();
VOID VOID
Stop(bool fServerInitiated) override; StopInternal(bool fServerInitiated) override;
virtual virtual
VOID VOID
OnAppOffline(); OnAppOffline();