winerror-0.1: System/Windows/Error.hs
{-# LANGUAGE CPP, DeriveDataTypeable, ForeignFunctionInterface #-}
{-# INCLUDE "HsWinError.h" #-}
{-# CFILES "cbits/HsWinError.c" #-}
{- |
Module : System.Windows.Error
Copyright : 2008 Felix Martini
License : BSD-style
Maintainer : fmartini@gmail.com
Stability : Provisional
Portability : Portable
Error handling for foreign calls to the Windows API.
-}
module System.Windows.Error
( WinError(..),
getWinError,
getWinErrorMessage,
throwWinError,
throwWinErrorIf,
throwWinErrorIfFalse,
throwWinErrorIfInvalidHandle,
#ifdef __GLASGOW_HASKELL__
catchWinError,
#endif
-- ** Common Windows error codes
-- | If the error code that you need is not listed below you can create your
-- own with the 'WinError' constructor and a numeric error code obtained from
-- the MSDN documentation at
-- <http://msdn2.microsoft.com/en-us/library/ms681381.aspx>. If you regularly
-- use an error code please contact the maintainer of this package to have it
-- included.
errorSuccess, errorInvalidFunction, errorFileNotFound,
errorPathNotFound, errorTooManyOpenFiles, errorAccessDenied,
errorInvalidHandle, errorArenaTrashed, errorNotEnoughMemory,
errorInvalidBlock, errorBadEnvironment, errorBadFormat,
errorInvalidAccess, errorInvalidData, errorOutOfMemory,
errorInvalidDrive, errorCurrentDirectory, errorNotReady,
errorHandleEOF,
) where
import Data.Word (Word32)
import Foreign.Ptr (Ptr)
import Foreign.C.String (CWString, peekCWString)
import System.IO.Error (mkIOError)
#ifdef __GLASGOW_HASKELL__
import GHC.IOBase (IOErrorType(DynIOError))
import Data.Dynamic (fromDynamic, toDyn)
import Data.Typeable (Typeable)
import System.IO.Error (ioeGetErrorType)
#else
import System.IO.Error (userErrorType)
#endif
newtype WinError = WinError Word32
#ifdef __GLASGOW_HASKELL__
deriving (Eq, Typeable)
#else
deriving Eq
#endif
instance Show WinError where
show (WinError err) = "Windows error " ++ show err
-- | Get the current thread's last error code. Each OS thread maintains it's
-- own last error code.
getWinError :: IO WinError
getWinError = do
err <- c_GetLastError
return (WinError err)
-- | Get the error message corresponding to the error code.
getWinErrorMessage :: WinError -- ^ Windows error code
-> IO String
getWinErrorMessage (WinError err) = do
msg <- c_GetErrorMessage err
str <- peekCWString msg
let str' = (unwords . words) str
c_LocalFree msg
return str'
-- | Throw an 'IOError' corresponding to the Windows error code. For GHC the
-- IOError type is DynIOError WinError. For other compilers the IOError type
-- is UserError.
throwWinError :: WinError -- ^ Windows error code
-> String -- ^ Textual description of the error location
-> IO a
throwWinError werr loc = do
str <- getWinErrorMessage werr
let loc' = loc ++ ": " ++ str ++ " (" ++ show werr ++ ")"
#ifdef __GLASGOW_HASKELL__
let ioe = mkIOError (DynIOError (toDyn werr)) loc' Nothing Nothing
#else
let ioe = mkIOError userErrorType loc' Nothing Nothing
#endif
ioError ioe
#ifdef __GLASGOW_HASKELL__
-- | Catch Windows errors. Other exceptions are not caught. Note that this
-- function is available only for GHC.
catchWinError :: IO a -- ^ The 'IO' operation to be executed
-> (WinError -> IO a) -- ^ Exception handler
-> IO a
catchWinError act h = catch act handle
where handle ex = case ioeGetErrorType ex of
DynIOError dyn ->
case fromDynamic dyn of
Just err -> h err
_other -> ioError ex
_other -> ioError ex
#endif
-- | Throw an 'IOError' corresponding to the last error code
-- if the result value of the 'IO' action meets the given predicate.
throwWinErrorIf :: (a -> Bool) -- ^ Predicate to apply to the result value
-- of the 'IO' operation
-> String -- ^ Textual description of the error location
-> IO a -- ^ The 'IO' action to be executed
-> IO a
throwWinErrorIf predicate loc act = do
res <- act
if predicate res
then do err <- c_GetLastError
throwWinError (WinError err) loc
else return res
-- | Throw an 'IOError' corresponding to the last error code if the result
-- value of the 'IO' action is False.
throwWinErrorIfFalse :: String -- ^ Textual description of the error location
-> IO Bool -- ^ The 'IO' action to be executed
-> IO ()
throwWinErrorIfFalse loc act = do
res <- act
if not res
then do err <- c_GetLastError
throwWinError (WinError err) loc
else return ()
-- | Throw an 'IOError' corresponding to the last error code if the result
-- value of the 'IO' action is an invalid handle.
throwWinErrorIfInvalidHandle :: String -- ^ Textual description of the
-- error location
-> IO (Ptr a) -- ^ The 'IO' action to be
-- executed
-> IO (Ptr a)
throwWinErrorIfInvalidHandle loc act = do
res <- act
if res == invalidHandleValue
then do err <- c_GetLastError
throwWinError (WinError err) loc
else return res
-- ---------------------------------------------------------------------
-- Error codes
errorSuccess, errorInvalidFunction, errorFileNotFound,
errorPathNotFound, errorTooManyOpenFiles, errorAccessDenied,
errorInvalidHandle, errorArenaTrashed, errorNotEnoughMemory,
errorInvalidBlock, errorBadEnvironment, errorBadFormat,
errorInvalidAccess, errorInvalidData, errorOutOfMemory,
errorInvalidDrive, errorCurrentDirectory, errorNotReady,
errorHandleEOF :: WinError
errorSuccess = WinError 0
errorInvalidFunction = WinError 1
errorFileNotFound = WinError 2
errorPathNotFound = WinError 3
errorTooManyOpenFiles = WinError 4
errorAccessDenied = WinError 5
errorInvalidHandle = WinError 6
errorArenaTrashed = WinError 7
errorNotEnoughMemory = WinError 8
errorInvalidBlock = WinError 9
errorBadEnvironment = WinError 10
errorBadFormat = WinError 11
errorInvalidAccess = WinError 12
errorInvalidData = WinError 13
errorOutOfMemory = WinError 14
errorInvalidDrive = WinError 15
errorCurrentDirectory = WinError 16
errorNotReady = WinError 21
errorHandleEOF = WinError 38
-- ---------------------------------------------------------------------
-- Foreign functions
foreign import stdcall unsafe "GetLastError"
c_GetLastError :: IO Word32
foreign import ccall unsafe "GetErrorMessageW"
c_GetErrorMessage :: Word32 -> IO CWString
foreign import stdcall unsafe "LocalFree"
c_LocalFree :: Ptr a -> IO (Ptr a)
foreign import ccall unsafe "invalidHandleValue"
invalidHandleValue :: Ptr a