Safe Haskell | Trustworthy |
---|---|
Language | Haskell2010 |
This module provides functions which can be used as drop-in replacements for Win32 when writing wrappers to foreign imports.
You will likely need to import modules from Win32 as well. To avoid accidentally calling the standard error handling functions it's a good idea to hide a few names:
import qualified System.Win32.Error.Foreign as E import System.Win32 hiding (failIfFalse_, failIf, failUnlessSuccess, failWith)
Handling error conditions in Windows revolves around a thread-local global variable representing the most recent error condition. Functions indicate that an error occurred in various ways. The C++ programmer will observe that a function failed, and immediately call GetLastError to retrieve details on the possible cause or to get a localized error message which can be relayed to a human in some way.
There are some cases where an error code may mean different things depending on varying context, but in general these codes are globally unique. Microsoft documents which error codes may be expected for any given function.
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 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 (simplified) wrapper around c_CreateFile could be written as follows. Source code from the Win32 package often provides a good starting point:
createFile name access mode = withTString name $ \ c_name -> E.failIf (== E.toDWORD E.InvalidHandle) "CreateFile" $ c_CreateFile c_name access fILE_SHARE_NONE nullPtr mode 0 nullPtr
Documentation
failIf :: (a -> Bool) -> Text -> IO a -> IO a Source #
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 () Source #
This function mirrors the Win32 package's failIfFalse_
function.
failIfNull :: Text -> IO (Ptr a) -> IO (Ptr a) Source #
This function mirrors the Win32 package's failIfNull
function.
failUnlessSuccess :: Text -> IO DWORD -> IO () Source #
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 Source #
Throw a Win32Exception
exception for the given function name and error code.
errorWin :: Text -> IO a Source #
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.