summaryrefslogtreecommitdiff
path: root/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp')
-rw-r--r--general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp b/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp
new file mode 100644
index 00000000..f6616850
--- /dev/null
+++ b/general/DCHU/osrfx2_DCHU_base/osrfx2_DCHU_usersvc/ServiceWin32API.cpp
@@ -0,0 +1,375 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ServiceWin32API.cpp
+
+Abstract:
+
+ Implements functions to start/run/stop the service.
+
+Environment:
+
+ User mode
+
+--*/
+
+#include "stdafx.h"
+
+//
+// Settings of the service
+//
+#define SERVICE_NAME L"OsrUsbFx2UmUserSvc"
+#define SERVICE_FLAGS_RUNNING 0x1
+
+//
+// Service context
+//
+SERVICE_STATUS_HANDLE SvcStatusHandle = NULL;
+volatile LONG SvcControlFlags = 0;
+HANDLE SvcStoppedEvent = NULL;
+HANDLE SvcStopRequestEvent = NULL;
+HANDLE SvcStopWaitObject = NULL;
+
+//
+// Device interface context
+//
+HCMNOTIFICATION InterfaceNotificationHandle = NULL;
+SRWLOCK DeviceListLock = SRWLOCK_INIT;
+DEVICE_LIST_ENTRY DeviceList;
+
+//
+// Debugging support during development time
+//
+//#define DEBUG_SUPPORT
+
+/*++
+
+Routine Description:
+
+ Entry point for the service.
+
+Arguments:
+
+ Argc - The number of command line arguments
+
+ Argv - The array of command line arguments
+
+Return Value:
+
+ VOID
+
+--*/
+INT
+wmain(
+ INT Argc,
+ WCHAR *Argv[]
+ )
+{
+ UNREFERENCED_PARAMETER(Argc);
+ UNREFERENCED_PARAMETER(Argv);
+
+ SERVICE_TABLE_ENTRY serviceTable[] =
+ {
+ { SERVICE_NAME, ServiceMain },
+ { NULL, NULL }
+ };
+
+ return StartServiceCtrlDispatcher(serviceTable);
+}
+
+VOID WINAPI ServiceMain(
+ DWORD Argc,
+ PWSTR *Argv
+ )
+{
+ DWORD Err = ERROR_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Argc);
+ UNREFERENCED_PARAMETER(Argv);
+
+ //
+ // Initialize global variables
+ //
+ InitializeDeviceListHead(&DeviceList);
+
+#ifdef DEBUG_SUPPORT
+
+ while (!IsDebuggerPresent()) {
+ Sleep(1000);
+ }
+
+ __debugbreak();
+
+#endif
+
+ SvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME,
+ ServiceCtrlHandler);
+
+ if (SvcStatusHandle == NULL)
+ {
+ Err = GetLastError();
+ goto cleanup;
+ }
+
+ UpdateServiceStatus(SvcStatusHandle,
+ SERVICE_START_PENDING,
+ ERROR_SUCCESS);
+
+ //
+ // Setup device interface context
+ //
+ Err = SetupDeviceInterfaceContext();
+
+ UpdateServiceStatus(SvcStatusHandle,
+ SERVICE_START_PENDING,
+ ERROR_SUCCESS);
+
+ //
+ // Initialize device control
+ //
+ OsrFx2InitializeDevice();
+
+ //
+ // Register callback function for stop event
+ //
+ SvcStopRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (SvcStopRequestEvent == NULL)
+ {
+ Err = GetLastError();
+ goto cleanup;
+ }
+
+ if (!RegisterWaitForSingleObject(&SvcStopWaitObject,
+ SvcStopRequestEvent,
+ ServiceStopCallback,
+ NULL,
+ INFINITE,
+ WT_EXECUTEONLYONCE | WT_EXECUTEINPERSISTENTTHREAD))
+ {
+ Err = GetLastError();
+ goto cleanup;
+ }
+
+ //
+ // Create stopped event for the running worker thread
+ //
+ SvcStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (SvcStoppedEvent == NULL)
+ {
+ Err = GetLastError();
+ goto cleanup;
+ }
+
+ UpdateServiceStatus(SvcStatusHandle,
+ SERVICE_START_PENDING,
+ ERROR_SUCCESS);
+
+ //
+ // Queue the main service function for execution in a worker thread.
+ //
+ QueueUserWorkItem(&ServiceRunningWorkerThread,
+ NULL,
+ WT_EXECUTELONGFUNCTION);
+
+ UpdateServiceStatus(SvcStatusHandle,
+ SERVICE_RUNNING,
+ ERROR_SUCCESS);
+
+cleanup:
+
+ if (Err != ERROR_SUCCESS)
+ {
+ ServiceStop(Err);
+ }
+}
+
+VOID
+WINAPI
+ServiceCtrlHandler(
+ DWORD Ctrl
+ )
+{
+ switch (Ctrl)
+ {
+ case SERVICE_CONTROL_STOP:
+ //
+ // Set service stop event
+ //
+ UpdateServiceStatus(SvcStatusHandle, SERVICE_STOP_PENDING, ERROR_SUCCESS);
+ SetEvent(SvcStopRequestEvent);
+ break;
+
+ default:
+ break;
+ }
+}
+
+#define SERVICE_WAIT_HINT_TIME 30000 // 30 seconds
+
+BOOL
+UpdateServiceStatus(
+ __in_opt SERVICE_STATUS_HANDLE hSvcHandle,
+ __in DWORD dwCurrentState,
+ __in DWORD dwWin32ExitCode
+ )
+{
+ SERVICE_STATUS SvcStatus;
+
+ static DWORD dwCheckPoint = 1;
+
+ SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ SvcStatus.dwCurrentState = dwCurrentState;
+ SvcStatus.dwWin32ExitCode = dwWin32ExitCode;
+ SvcStatus.dwServiceSpecificExitCode = ERROR_SUCCESS;
+
+ if (dwCurrentState == SERVICE_START_PENDING)
+ {
+ SvcStatus.dwControlsAccepted = 0;
+ }
+ else
+ {
+ SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ }
+
+ if ((dwCurrentState == SERVICE_RUNNING) ||
+ (dwCurrentState == SERVICE_STOPPED))
+ {
+ SvcStatus.dwCheckPoint = 0;
+ SvcStatus.dwWaitHint = 0;
+ }
+ else
+ {
+ SvcStatus.dwCheckPoint = dwCheckPoint++;
+ SvcStatus.dwWaitHint = SERVICE_WAIT_HINT_TIME;
+ }
+
+ return SetServiceStatus(hSvcHandle, &SvcStatus);
+}
+
+DWORD
+WINAPI
+ServiceRunningWorkerThread(
+ _In_ PVOID lpThreadParameter
+ )
+{
+ PDEVICE_CONTEXT DeviceContext = NULL;
+ PDEVICE_LIST_ENTRY Link = NULL;
+
+ UNREFERENCED_PARAMETER(lpThreadParameter);
+
+ InterlockedOr(&SvcControlFlags, SERVICE_FLAGS_RUNNING);
+
+ //
+ // Periodically check if the service is stopping.
+ //
+ while ((InterlockedOr(&SvcControlFlags, 0) & SERVICE_FLAGS_RUNNING) != 0)
+ {
+ AcquireSRWLockShared(&DeviceListLock);
+
+ for (Link = DeviceList.Flink; Link != &DeviceList; Link = Link->Flink)
+ {
+ DeviceContext = CONTAINING_DEVICE_RECORD(Link);
+
+ OsrFx2ControlDevice(DeviceContext);
+ }
+
+ ReleaseSRWLockShared(&DeviceListLock);
+
+ Sleep(2000); // Simulate some lengthy operations.
+ }
+
+ //
+ // Signal the stopped event.
+ //
+ SetEvent(SvcStoppedEvent);
+
+ return 0;
+}
+
+VOID
+CALLBACK
+ServiceStopCallback(
+ _In_ PVOID lpParameter,
+ _In_ BOOLEAN TimerOrWaitFired
+ )
+{
+ UNREFERENCED_PARAMETER(TimerOrWaitFired);
+
+ //
+ // Since wait object can not be unregistered in callback function, queue
+ // another thread
+ //
+ QueueUserWorkItem(ServiceStopWorkerThread,
+ lpParameter,
+ WT_EXECUTEDEFAULT);
+}
+
+DWORD
+WINAPI
+ServiceStopWorkerThread(
+ _In_ PVOID lpThreadParameter
+ )
+{
+ UNREFERENCED_PARAMETER(lpThreadParameter);
+
+ ServiceStop(ERROR_SUCCESS);
+
+ return 0;
+}
+
+VOID
+ServiceStop(
+ _In_ DWORD ExitCode
+ )
+{
+ if (SvcStatusHandle == NULL)
+ {
+ return;
+ }
+
+ UpdateServiceStatus(SvcStatusHandle, SERVICE_STOP_PENDING, ExitCode);
+
+ //
+ // Notify the working thread to stop
+ //
+ if ((InterlockedOr(&SvcControlFlags, 0) & SERVICE_FLAGS_RUNNING) != 0)
+ {
+ InterlockedAnd(&SvcControlFlags, ~SERVICE_FLAGS_RUNNING);
+ WaitForSingleObject(SvcStoppedEvent, INFINITE);
+ }
+
+ //
+ // Clean up device context after the worker thread has finished.
+ //
+ CleanupDeviceInterfaceContext();
+
+ //
+ // cleanup work
+ //
+ if (SvcStopWaitObject != NULL)
+ {
+ UnregisterWait(SvcStopWaitObject);
+ }
+
+ if (SvcStopRequestEvent != NULL)
+ {
+ CloseHandle(SvcStopRequestEvent);
+ }
+
+ if (SvcStoppedEvent != NULL)
+ {
+ CloseHandle(SvcStoppedEvent);
+ }
+
+ UpdateServiceStatus(SvcStatusHandle, SERVICE_STOPPED, ExitCode);
+}