diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj
index 82b3ef51..8b634a97 100644
--- a/build/VStudio/winfsp_dll.vcxproj
+++ b/build/VStudio/winfsp_dll.vcxproj
@@ -25,6 +25,7 @@
+
@@ -34,6 +35,7 @@
+
diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters
index df52df4a..bc3fc63d 100644
--- a/build/VStudio/winfsp_dll.vcxproj.filters
+++ b/build/VStudio/winfsp_dll.vcxproj.filters
@@ -52,6 +52,12 @@
Source
+
+ Source
+
+
+ Source
+
diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h
index e473feac..451a4fed 100644
--- a/inc/winfsp/winfsp.h
+++ b/inc/winfsp/winfsp.h
@@ -838,10 +838,52 @@ FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain, PWSTR Roo
FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix, PWSTR Root);
FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix);
+/*
+ * Service Framework
+ */
+typedef struct _FSP_SERVICE FSP_SERVICE;
+typedef NTSTATUS FSP_SERVICE_START(FSP_SERVICE *, ULONG, PWSTR *);
+typedef NTSTATUS FSP_SERVICE_STOP(FSP_SERVICE *);
+typedef NTSTATUS FSP_SERVICE_CONTROL(FSP_SERVICE *, ULONG, ULONG, PVOID);
+#pragma warning(push)
+#pragma warning(disable:4200) /* zero-sized array in struct/union */
+typedef struct _FSP_SERVICE
+{
+ UINT16 Version;
+ PVOID UserContext;
+ FSP_SERVICE_START *OnStart;
+ FSP_SERVICE_STOP *OnStop;
+ FSP_SERVICE_CONTROL *OnControl;
+ ULONG AcceptControl;
+ ULONG ExitCode;
+ SERVICE_STATUS_HANDLE StatusHandle;
+ CRITICAL_SECTION ServiceStatusGuard;
+ SERVICE_STATUS ServiceStatus;
+ BOOLEAN AllowInteractive;
+ HANDLE InteractiveEvent;
+ WCHAR ServiceName[];
+} FSP_SERVICE;
+#pragma warning(pop)
+FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
+ FSP_SERVICE_START *OnStart,
+ FSP_SERVICE_STOP *OnStop,
+ FSP_SERVICE_CONTROL *OnControl,
+ FSP_SERVICE **PService);
+FSP_API VOID FspServiceDelete(FSP_SERVICE *Service);
+FSP_API VOID FspServiceAllowInteractive(FSP_SERVICE *Service);
+FSP_API VOID FspServiceAcceptControl(FSP_SERVICE *Service, ULONG Control);
+FSP_API VOID FspServiceRequestTime(FSP_SERVICE *Service, ULONG Time);
+FSP_API VOID FspServiceSetExitCode(FSP_SERVICE *Service, ULONG ExitCode);
+FSP_API NTSTATUS FspServiceRun(FSP_SERVICE *Service);
+FSP_API VOID FspServiceStop(FSP_SERVICE *Service);
+
/*
* Utility
*/
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error);
+FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status);
+FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...);
+FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap);
FSP_API VOID FspDebugLog(const char *format, ...);
FSP_API VOID FspDebugLogSD(const char *format, PSECURITY_DESCRIPTOR SecurityDescriptor);
FSP_API VOID FspDebugLogFT(const char *format, PFILETIME FileTime);
diff --git a/src/dll/eventlog.c b/src/dll/eventlog.c
new file mode 100644
index 00000000..fb992e9b
--- /dev/null
+++ b/src/dll/eventlog.c
@@ -0,0 +1,56 @@
+/**
+ * @file dll/eventlog.c
+ *
+ * @copyright 2015-2016 Bill Zissimopoulos
+ */
+/*
+ * This file is part of WinFsp.
+ *
+ * You can redistribute it and/or modify it under the terms of the
+ * GNU Affero General Public License version 3 as published by the
+ * Free Software Foundation.
+ *
+ * Licensees holding a valid commercial license may use this file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#include
+#include
+
+static HANDLE FspEventLogHandle;
+static INIT_ONCE FspEventLogInitOnce = INIT_ONCE_STATIC_INIT;
+static BOOL WINAPI FspEventLogRegisterEventSource(
+ PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context);
+
+FSP_API VOID FspEventLog(ULONG Type, PWSTR Format, ...)
+{
+ va_list ap;
+
+ va_start(ap, Format);
+ FspEventLogV(Type, Format, ap);
+ va_end(ap);
+}
+
+FSP_API VOID FspEventLogV(ULONG Type, PWSTR Format, va_list ap)
+{
+ InitOnceExecuteOnce(&FspEventLogInitOnce, FspEventLogRegisterEventSource, 0, 0);
+ if (0 == FspEventLogHandle)
+ return;
+
+ WCHAR Buf[1024], *Strings[1];
+ /* wvsprintfW is only safe with a 1024 WCHAR buffer */
+
+ wvsprintfW(Buf, Format, ap);
+ Buf[(sizeof Buf / sizeof Buf[0]) - 1] = L'\0';
+
+ Strings[0] = Buf;
+ ReportEventW(FspEventLogHandle, (WORD)Type, 0, 1, 0, 1, 0, Strings, 0);
+}
+
+static BOOL WINAPI FspEventLogRegisterEventSource(
+ PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
+{
+ FspEventLogHandle = RegisterEventSourceW(0, L"" LIBRARY_NAME);
+ return TRUE;
+}
diff --git a/src/dll/library.c b/src/dll/library.c
index 4233120f..ab63664e 100644
--- a/src/dll/library.c
+++ b/src/dll/library.c
@@ -29,6 +29,7 @@ BOOL WINAPI DllMain(HINSTANCE Instance, DWORD Reason, PVOID Reserved)
ProcessHeap = GetProcessHeap();
if (0 == ProcessHeap)
return FALSE;
+ FspNtStatusInitialize();
FspFileSystemInitialize();
break;
case DLL_PROCESS_DETACH:
diff --git a/src/dll/library.h b/src/dll/library.h
index 40aa6c12..c71c3f63 100644
--- a/src/dll/library.h
+++ b/src/dll/library.h
@@ -103,6 +103,8 @@ BOOLEAN RemoveEntryList(PLIST_ENTRY Entry)
return Flink == Blink;
}
+VOID FspNtStatusInitialize(VOID);
+
VOID FspFileSystemInitialize(VOID);
VOID FspFileSystemFinalize(VOID);
diff --git a/src/dll/ntstatus.c b/src/dll/ntstatus.c
index a37b0eb6..25a78167 100644
--- a/src/dll/ntstatus.c
+++ b/src/dll/ntstatus.c
@@ -17,6 +17,25 @@
#include
+static ULONG (WINAPI *FspRtlNtStatusToDosError)(NTSTATUS Status);
+
+VOID FspNtStatusInitialize(VOID)
+{
+ /*
+ * This function is called during DLL_PROCESS_ATTACH. We must therefore keep initialization
+ * tasks to a minimum.
+ *
+ * GetModuleHandle/GetProcAddress is allowed (because they are kernel32 API's)! See:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971(v=vs.85).aspx
+ */
+
+ HANDLE Handle;
+
+ Handle = GetModuleHandleW(L"ntdll.dll");
+ if (0 != Handle)
+ FspRtlNtStatusToDosError = (PVOID)GetProcAddress(Handle, "RtlNtStatusToDosError");
+}
+
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
{
switch (Error)
@@ -26,3 +45,11 @@ FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error)
return STATUS_ACCESS_DENIED;
}
}
+
+FSP_API DWORD FspWin32FromNtStatus(NTSTATUS Status)
+{
+ if (0 == FspRtlNtStatusToDosError)
+ return ERROR_MR_MID_NOT_FOUND;
+
+ return FspRtlNtStatusToDosError(Status);
+}
diff --git a/src/dll/service.c b/src/dll/service.c
new file mode 100644
index 00000000..6f163611
--- /dev/null
+++ b/src/dll/service.c
@@ -0,0 +1,418 @@
+/**
+ * @file dll/service.c
+ *
+ * @copyright 2015-2016 Bill Zissimopoulos
+ */
+/*
+ * This file is part of WinFsp.
+ *
+ * You can redistribute it and/or modify it under the terms of the
+ * GNU Affero General Public License version 3 as published by the
+ * Free Software Foundation.
+ *
+ * Licensees holding a valid commercial license may use this file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#include
+
+// !!!: NOTIMPLEMENTED
+#define FspEventLog(Type, Message, ...)
+
+enum
+{
+ SetStatus_ServiceType = 0x0001,
+ SetStatus_CurrentState = 0x0002,
+ SetStatus_ControlsAccepted = 0x0004,
+ SetStatus_Win32ExitCode = 0x0008,
+ SetStatus_ServiceSpecificExitCode = 0x0010,
+ SetStatus_CheckPoint = 0x0020,
+ SetStatus_WaitHint = 0x0040,
+ GetStatus_ServiceType = 0x0100,
+ GetStatus_CurrentState = 0x0200,
+ GetStatus_ControlsAccepted = 0x0400,
+ GetStatus_Win32ExitCode = 0x0800,
+ GetStatus_ServiceSpecificExitCode = 0x1000,
+ GetStatus_CheckPoint = 0x2000,
+ GetStatus_WaitHint = 0x4000,
+};
+
+static SERVICE_TABLE_ENTRYW *FspServiceTable;
+static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus);
+static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv);
+static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv);
+static DWORD WINAPI FspServiceCtrlHandler(
+ DWORD Control, DWORD EventType, PVOID EventData, PVOID Context);
+static DWORD WINAPI FspServiceStopRoutine(PVOID Context);
+static DWORD WINAPI FspServiceInteractiveThread(PVOID Context);
+static BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType);
+
+static inline FSP_SERVICE *FspServiceFromTable(VOID)
+{
+ FSP_SERVICE *Service = 0;
+
+ if (0 != FspServiceTable)
+ {
+ Service = (PVOID)((PUINT8)FspServiceTable[0].lpServiceName -
+ FIELD_OFFSET(FSP_SERVICE, ServiceName));
+ FspServiceTable = 0;
+ }
+
+ return Service;
+}
+
+FSP_API NTSTATUS FspServiceCreate(PWSTR ServiceName,
+ FSP_SERVICE_START *OnStart,
+ FSP_SERVICE_STOP *OnStop,
+ FSP_SERVICE_CONTROL *OnControl,
+ FSP_SERVICE **PService)
+{
+ FSP_SERVICE *Service;
+ DWORD Size;
+
+ *PService = 0;
+
+ Size = (lstrlenW(ServiceName) + 1) * sizeof(WCHAR);
+
+ Service = MemAlloc(sizeof *Service + Size);
+ if (0 == Service)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ memset(Service, 0, sizeof *Service);
+ memcpy(Service->ServiceName, ServiceName, Size);
+
+ Service->OnStart = OnStart;
+ Service->OnStop = OnStop;
+ Service->OnControl = OnControl;
+
+ Service->AcceptControl = OnStop ? SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN : 0;
+
+ InitializeCriticalSection(&Service->ServiceStatusGuard);
+ Service->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ Service->ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ Service->ServiceStatus.dwControlsAccepted = 0;
+ Service->ServiceStatus.dwWin32ExitCode = NO_ERROR;
+ Service->ServiceStatus.dwServiceSpecificExitCode = 0;
+ Service->ServiceStatus.dwCheckPoint = 0;
+ Service->ServiceStatus.dwWaitHint = 0;
+
+ *PService = Service;
+
+ return STATUS_SUCCESS;
+}
+
+FSP_API VOID FspServiceDelete(FSP_SERVICE *Service)
+{
+ if (0 != Service->InteractiveEvent)
+ CloseHandle(Service->InteractiveEvent);
+
+ DeleteCriticalSection(&Service->ServiceStatusGuard);
+ MemFree(Service);
+}
+
+static VOID FspServiceSetStatus(FSP_SERVICE *Service, ULONG Flags, SERVICE_STATUS *ServiceStatus)
+{
+#define XCHG(FIELD)\
+ if (Flags & SetStatus_##FIELD)\
+ {\
+ DWORD Temp = ServiceStatus->dw##FIELD;\
+ if (Flags & GetStatus_##FIELD)\
+ ServiceStatus->dw##FIELD = Service->ServiceStatus.dw##FIELD;\
+ Service->ServiceStatus.dw##FIELD = Temp;\
+ }
+
+ EnterCriticalSection(&Service->ServiceStatusGuard);
+
+ //XCHG(ServiceType);
+ XCHG(CurrentState);
+ XCHG(ControlsAccepted);
+ XCHG(Win32ExitCode);
+ //XCHG(ServiceSpecificExitCode);
+ if (Flags & SetStatus_CheckPoint)
+ {
+ DWORD Temp = ServiceStatus->dwCheckPoint;
+ if (Flags & GetStatus_CheckPoint)
+ ServiceStatus->dwCheckPoint = Service->ServiceStatus.dwCheckPoint;
+
+ /* treat CheckPoint specially! */
+ if (0 == Temp)
+ Service->ServiceStatus.dwCheckPoint = 0;
+ else
+ Service->ServiceStatus.dwCheckPoint += Temp;
+ }
+ XCHG(WaitHint);
+
+ if (0 != Service->StatusHandle)
+ {
+ if (!SetServiceStatus(Service->StatusHandle, &Service->ServiceStatus))
+ FspEventLog(EVENTLOG_ERROR_TYPE,
+ L"" __FUNCTION__ ": error = %ld", GetLastError());
+ }
+ else if (0 != Service->InteractiveEvent &&
+ SERVICE_STOPPED == Service->ServiceStatus.dwCurrentState)
+ {
+ SetEvent(Service->InteractiveEvent);
+ }
+
+ LeaveCriticalSection(&Service->ServiceStatusGuard);
+
+#undef XCHG
+}
+
+FSP_API VOID FspServiceAllowInteractive(FSP_SERVICE *Service)
+{
+ Service->AllowInteractive = TRUE;
+}
+
+FSP_API VOID FspServiceAcceptControl(FSP_SERVICE *Service, ULONG Control)
+{
+ Service->AcceptControl = Control & ~SERVICE_ACCEPT_PAUSE_CONTINUE;
+}
+
+FSP_API VOID FspServiceRequestTime(FSP_SERVICE *Service, ULONG Time)
+{
+ SERVICE_STATUS ServiceStatus;
+
+ ServiceStatus.dwCheckPoint = +1;
+ ServiceStatus.dwWaitHint = Time;
+ FspServiceSetStatus(Service,
+ SetStatus_CheckPoint | SetStatus_WaitHint, &ServiceStatus);
+}
+
+FSP_API VOID FspServiceSetExitCode(FSP_SERVICE *Service, ULONG ExitCode)
+{
+ Service->ExitCode = ExitCode;
+}
+
+FSP_API NTSTATUS FspServiceRun(FSP_SERVICE *Service)
+{
+ SERVICE_TABLE_ENTRYW ServiceTable[2];
+
+ ServiceTable[0].lpServiceName = Service->ServiceName;
+ ServiceTable[0].lpServiceProc = FspServiceEntry;
+ ServiceTable[1].lpServiceName = 0;
+ ServiceTable[1].lpServiceProc = 0;
+ FspServiceTable = ServiceTable;
+
+ if (!StartServiceCtrlDispatcherW(ServiceTable))
+ {
+ HANDLE Thread;
+ DWORD WaitResult;
+ DWORD LastError;
+
+ LastError = GetLastError();
+ if (!Service->AllowInteractive || ERROR_FAILED_SERVICE_CONTROLLER_CONNECT != LastError)
+ return FspNtStatusFromWin32(LastError);
+
+ /* enter INTERACTIVE (DEBUG) mode! */
+
+ Service->InteractiveEvent = CreateEventW(0, TRUE, FALSE, 0);
+ if (0 == Service->InteractiveEvent)
+ return FspNtStatusFromWin32(GetLastError());
+
+ Thread = CreateThread(0, 0, FspServiceInteractiveThread, Service, 0, 0);
+ if (0 == Thread)
+ return FspNtStatusFromWin32(GetLastError());
+ WaitResult = WaitForSingleObject(Thread, INFINITE);
+ CloseHandle(Thread);
+ if (WAIT_OBJECT_0 != WaitResult)
+ return FspNtStatusFromWin32(GetLastError());
+
+ if (!SetConsoleCtrlHandler(FspServiceConsoleCtrlHandler, TRUE))
+ return FspNtStatusFromWin32(GetLastError());
+
+ WaitResult = WaitForSingleObject(Service->InteractiveEvent, INFINITE);
+ if (WAIT_OBJECT_0 != WaitResult)
+ return FspNtStatusFromWin32(GetLastError());
+ }
+
+ return STATUS_SUCCESS;
+}
+
+FSP_API VOID FspServiceStop(FSP_SERVICE *Service)
+{
+ SERVICE_STATUS ServiceStatus;
+ NTSTATUS Result;
+
+ ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ ServiceStatus.dwCheckPoint = 0;
+ ServiceStatus.dwWaitHint = 0;
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint |
+ GetStatus_CurrentState | GetStatus_CheckPoint | GetStatus_WaitHint,
+ &ServiceStatus);
+
+ Result = STATUS_SUCCESS;
+ if (0 != Service->OnStop)
+ Result = Service->OnStop(Service);
+
+ if (NT_SUCCESS(Result))
+ {
+ ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ ServiceStatus.dwWin32ExitCode = Service->ExitCode;
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
+ }
+ else
+ {
+ /* revert the service status */
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_CheckPoint | SetStatus_WaitHint,
+ &ServiceStatus);
+ }
+}
+
+static VOID WINAPI FspServiceEntry(DWORD Argc, PWSTR *Argv)
+{
+ FSP_SERVICE *Service;
+
+ Service = FspServiceFromTable();
+ if (0 == Service)
+ {
+ FspEventLog(EVENTLOG_ERROR_TYPE,
+ L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
+ return;
+ }
+
+ Service->StatusHandle = RegisterServiceCtrlHandlerExW(Service->ServiceName,
+ FspServiceCtrlHandler, Service);
+ if (0 == Service->StatusHandle)
+ {
+ FspEventLog(EVENTLOG_ERROR_TYPE,
+ L"" __FUNCTION__ ": RegisterServiceCtrlHandlerW = %ld", GetLastError());
+ return;
+ }
+
+ FspServiceMain(Service, Argc, Argv);
+}
+
+static VOID FspServiceMain(FSP_SERVICE *Service, DWORD Argc, PWSTR *Argv)
+{
+ SERVICE_STATUS ServiceStatus;
+ NTSTATUS Result;
+
+ ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+ ServiceStatus.dwControlsAccepted = 0;
+ ServiceStatus.dwCheckPoint = 0;
+ ServiceStatus.dwWaitHint = 0;
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_ControlsAccepted | SetStatus_CheckPoint | SetStatus_WaitHint,
+ &ServiceStatus);
+
+ Result = STATUS_SUCCESS;
+ if (0 != Service->OnStart)
+ Result = Service->OnStart(Service, Argc, Argv);
+
+ if (NT_SUCCESS(Result))
+ {
+ ServiceStatus.dwCurrentState = SERVICE_RUNNING;
+ ServiceStatus.dwControlsAccepted = Service->AcceptControl;
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_ControlsAccepted, &ServiceStatus);
+ }
+ else
+ {
+ ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ ServiceStatus.dwWin32ExitCode = FspWin32FromNtStatus(Result);
+ FspServiceSetStatus(Service,
+ SetStatus_CurrentState | SetStatus_Win32ExitCode, &ServiceStatus);
+ }
+}
+
+static DWORD WINAPI FspServiceCtrlHandler(
+ DWORD Control, DWORD EventType, PVOID EventData, PVOID Context)
+{
+ FSP_SERVICE *Service = Context;
+ NTSTATUS Result;
+
+ switch (Control)
+ {
+ case SERVICE_CONTROL_SHUTDOWN:
+ Result = STATUS_NOT_IMPLEMENTED;
+ if (0 != Service->OnControl)
+ Result = Service->OnControl(Service, Control, EventType, EventData);
+ if (STATUS_NOT_IMPLEMENTED != Result)
+ return FspWin32FromNtStatus(Result);
+ /* fall through */
+
+ case SERVICE_CONTROL_STOP:
+ if (!QueueUserWorkItem(FspServiceStopRoutine, Service, WT_EXECUTEDEFAULT))
+ FspServiceStopRoutine(Service);
+ return NO_ERROR;
+
+ case SERVICE_CONTROL_PAUSE:
+ case SERVICE_CONTROL_CONTINUE:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+
+ default:
+ Result = STATUS_SUCCESS;
+ if (0 != Service->OnControl)
+ Result = Service->OnControl(Service, Control, EventType, EventData);
+ return FspWin32FromNtStatus(Result);
+ }
+}
+
+static DWORD WINAPI FspServiceStopRoutine(PVOID Context)
+{
+ FSP_SERVICE *Service = Context;
+
+ FspServiceStop(Service);
+ return 0;
+}
+
+static DWORD WINAPI FspServiceInteractiveThread(PVOID Context)
+{
+ FSP_SERVICE *Service;
+ PWSTR Args[2] = { 0, 0 };
+ PWSTR *Argv;
+ DWORD Argc;
+
+ Service = FspServiceFromTable();
+ if (0 == Service)
+ {
+ FspEventLog(EVENTLOG_ERROR_TYPE,
+ L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
+ return FALSE;
+ }
+
+ Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
+ if (0 == Argv)
+ {
+ Argv = Args;
+ Argc = 1;
+ }
+ Argv[0] = Service->ServiceName;
+
+ FspServiceMain(Service, Argc, Argv);
+
+ if (Args != Argv)
+ LocalFree(Argv);
+
+ return 0;
+}
+
+static BOOL WINAPI FspServiceConsoleCtrlHandler(DWORD CtrlType)
+{
+ FSP_SERVICE *Service;
+
+ Service = FspServiceFromTable();
+ if (0 == Service)
+ {
+ FspEventLog(EVENTLOG_ERROR_TYPE,
+ L"" __FUNCTION__ ": internal error: FspServiceFromTable = 0");
+ return FALSE;
+ }
+
+ switch (CtrlType)
+ {
+ case CTRL_SHUTDOWN_EVENT:
+ FspServiceCtrlHandler(SERVICE_CONTROL_SHUTDOWN, 0, 0, Service);
+ return TRUE;
+ default:
+ FspServiceCtrlHandler(SERVICE_CONTROL_STOP, 0, 0, Service);
+ return TRUE;
+ }
+}