Win32-services-wrapper-0.1.0.0: src/System/Win32/SystemServices/Wrapper.hs
{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables
#-}
module System.Win32.SystemServices.Wrapper
( Service(..)
, defineService
) where
import Prelude hiding ( catch )
import Control.Concurrent ( MVar, newEmptyMVar, putMVar, takeMVar )
import Control.Exception ( catch, throwIO, SomeException )
import System.Directory ( getTemporaryDirectory )
import System.FilePath ( (</>) )
import System.IO
( hSetBuffering, BufferMode(NoBuffering)
, openFile, IOMode(WriteMode)
, Handle, hPutStrLn
)
import System.Win32.SystemServices.Services
( SERVICE_STATUS(..), SERVICE_STATE(..)
, SERVICE_CONTROL(..), SERVICE_ACCEPT(..), SERVICE_TYPE(..)
, setServiceStatus, startServiceCtrlDispatcher
, nO_ERROR
)
import System.Win32.Types ( HANDLE, DWORD )
data Service serviceState =
Service {
serviceName :: String
, serviceStart :: Handle -> IO serviceState
, serviceStop :: serviceState -> IO ()
}
handler :: MVar () -> HANDLE -> SERVICE_CONTROL -> IO Bool
handler stopSignal hStatus STOP = do
setServiceStatus hStatus stopPending
putMVar stopSignal ()
return True
handler _ _ INTERROGATE = return True
handler _ _ _ = return False
running, stopPending, stopped :: SERVICE_STATUS
running = SERVICE_STATUS WIN32_OWN_PROCESS RUNNING [ACCEPT_STOP] nO_ERROR 0 0 0
stopPending = running { currentState = STOP_PENDING
, controlsAccepted = []
, waitHint = 3000 }
stopped = running { currentState = STOPPED
, controlsAccepted = []
, waitHint = 3000 }
logExceptions :: Handle -> IO a -> IO a
logExceptions h comp =
comp `catch`
\(e :: SomeException) -> do
hPutStrLn h (show e)
throwIO e
foreign import stdcall "GetCurrentProcessId" getCurrentProcessId :: IO DWORD
defineService :: Service serviceState -> IO ()
defineService svc = do
pid <- getCurrentProcessId
temp <- getTemporaryDirectory
let logFile = temp </> ("service-debug-" ++ serviceName svc ++ "-" ++ show pid ++ ".log")
debugH <- openFile logFile WriteMode
hSetBuffering debugH NoBuffering
stopSignal <- newEmptyMVar
startServiceCtrlDispatcher
(serviceName svc)
3000
(handler stopSignal)
(\_ _ h ->
logExceptions debugH $ do
state <- serviceStart svc debugH
setServiceStatus h running
takeMVar stopSignal
serviceStop svc state
setServiceStatus h stopped
)