| Portability | Windows |
|---|---|
| Stability | experimental |
| Maintainer | mikesteele81@gmail.com |
| Safe Haskell | None |
System.Win32.Errors
Contents
Description
This module is intended to be imported qualified.
import System.Win32.Errors (ErrCode, Win32Exception) import qualified System.Win32.Errors as E
If you are writing your own bindings to parts of the Win32, consider hiding some names from the Win32 package which deal with error handling to avoid accidentally using them:
import System.Win32 hiding (failIfFalse_, failIf, failUnlessSuccess, failWith)
This package and others written by the author assume that you will be using
strict Text values for string handling. Consider using the following import
statements:
import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Foreign as T
Comparison with the Win32 package:
When working with functions exported by Win32, error conditions are dealt
with using the IOError exception type. Most native Win32 functions return
an error code which can be used to determine whether something went wrong
during its execution. By convention these functions are all named something
of the form c_DoSomething where DoSomething matches the name given by
Microsoft. A haskell wrapper function named doSomething will typically,
among other things, check this error code. Based on its value the operating
system will be queried for additional error information, and a Haskell
exception will be thrown.
Consider the createFile function, which can be used to
open existing files which may or may not actually exist.
createFile "c:\\nofilehere.txt" gENERIC_READ
fILE_SHARE_NONE Nothing oPEN_EXISTING 0 Nothing
If no file by that name exists the underlying c_CreateFile call will
return iNVALID_HANDLE_VALUE. This will result in an IOError exception
being thrown with a String value indicating the function and file name.
Internally, the IOError will also contain the error code, which will be
converted to a general Haskell value.
The Win32-errors package works similarly. A user might write ones own (simplified) wrapper around c_CreateFile as follows. Source code from the Win32 package often provides a good starting point:
createFile name access mode = withTString name $ \ c_name ->
E.failIf (== toDWORD E.InvalidHandle) "CreateFile" $
c_CreateFile c_name access fILE_SHARE_NONE nullPtr
mode 0 nullPtr
The easiest way to handle error conditions is by wrapping an IO computation
containing Win32 calls in a call to tryWin32:
eHandle <- do
h <- E.tryWin32 $ createFile "c:\\nofilehere.txt" gENERIC_READ
oPEN_EXISTING
-- perform other actions
return h
case eHandle of
Right handle -> do
-- do something with the file handle
Left w32Err -> do
case E.errCode w32Err of
E.InvalidHandle -> do
-- perform cleanup
-- handle other error codes.
T.putStrLn $ E.systemMessage w32Err
- tryWin32 :: IO a -> IO (Either Win32Exception a)
- failIf :: (a -> Bool) -> Text -> IO a -> IO a
- failIfFalse_ :: Text -> IO Bool -> IO ()
- failIfNull :: Text -> IO (Ptr a) -> IO (Ptr a)
- failUnlessSuccess :: Text -> IO DWORD -> IO ()
- failWith :: Text -> ErrCode -> IO a
- errorWin :: Text -> IO a
- data ErrCode
- = InvalidHandleValue
- | Success
- | FileNotFound
- | PathNotFound
- | AccessDenied
- | InvalidHandle
- | InvalidData
- | InvalidDrive
- | CurrentDirectory
- | NoMoreFiles
- | CallNotImplemented
- | MoreData
- | NoMoreItems
- | ServiceAlreadyRunning
- | ServiceDisabled
- | ServiceDoesNotExist
- | ServiceCannotAcceptCtrl
- | ServiceNotActive
- | FailedServiceControllerConnect
- | ExceptionInService
- | ServiceSpecificError
- | ServiceNotInExe
- | NotAReparsePoint
- | DhcpSubnetNotPresent
- | DhcpElementCantRemove
- | DhcpOptionNotPresent
- | DhcpJetError
- | DhcpNotReservedClient
- | DhcpInvalidRange
- | Other !DWORD
- toDWORD :: ErrCode -> DWORD
- fromDWORD :: DWORD -> ErrCode
- data Win32Exception = Win32Exception {}
Documentation
tryWin32 :: IO a -> IO (Either Win32Exception a)
Actions calling out to Win32 may throw exceptions. Wrapping the action in
tryWin32 will catch Win32Exception exceptions, but will allow any other
exception type to pass through.
Triggering Errors
failIf :: (a -> Bool) -> Text -> IO a -> IO a
Copied from the Win32 package. Use this to throw a Win32 exception
when an action returns a value satisfying the given predicate.
The exception thrown will depend on a thead-local global error condition.
The supplied Text value should be set to the human-friendly name of the
action that triggered the error.
failIfFalse_ :: Text -> IO Bool -> IO ()
This function mirrors the Win32 package's failIfFalse_
function.
failIfNull :: Text -> IO (Ptr a) -> IO (Ptr a)
This function mirrors the Win32 package's failIfNull
function.
failUnlessSuccess :: Text -> IO DWORD -> IO ()
Perform the supplied action, and throw a Win32Exception exception if the
return code is anything other than Success. The supplied action returns
a DWORD instead of an ErrCode so that foreign imports can be used more
conveniently.
failWith :: Text -> ErrCode -> IO a
Throw a Win32Exception exception for the given function name and error code.
Windows maintains a thread-local value representing the previously triggered
error code. Calling errorWin will look up the value, and throw a Win32Exception
exception. The supplied Text argument should be set to the name of the function
which triggered the error condition.
Calling this action when no error has occurred (0x00000000 -- ERROR_SUCCESS) will
result in an exception being thrown for the Success error code.
Error Types
data ErrCode
Win32 actions typically return an error code to indicate success or failure. These codes are intended to be globally unique, though there may be some overlap. MSDN documents which errors may be returned by any given action.
The naming of errors follows a convention. An error such as ERROR_SUCCESS
becomes Success, ERROR_FILE_NOT_FOUND becomes FileNotFound, and so
on. There are thousands of errors, so it would be impractical to add them
all. The Other constructor is used to represent error codes which are not
handled specifically.
User's of this library are encouraged to submit new error codes. Add new entries to System.Win32.Errors.Mapping. Send your pull requests along with a link to relevent documentation to https://github.com/mikesteele81/Win32-errors.git.
Constructors