packages feed

Win32-extras-0.1.0.0: System/Win32/DLL/LoadFunction.hs

{-# LANGUAGE CPP #-}
{- |
   Module      :  System.Win32.DLL.LoadFunction
   Copyright   :  2012 shelarcy
   License     :  BSD-style

   Maintainer  :  shelarcy@gmail.com
   Stability   :  Provisional
   Portability :  Non-portable (Win32 API)

   Load a DLL's function.
-}
module System.Win32.DLL.LoadFunction
  ( module System.Win32.DLL.LoadFunction
  ) where
import Control.Exception            ( bracket, mask, finally )
import Foreign.C.String             ( withCAString )
import Foreign.Ptr                  ( FunPtr, castPtrToFunPtr )
import System.Win32.Error           ( failIfFalse_ )
import System.Win32.Exception.Unsupported
import System.Win32.DLL             ( c_GetProcAddress, c_LoadLibrary, freeLibrary, getModuleHandle )
import System.Win32.Types hiding    ( failIfFalse_ )
----------------------------------------------------------------
-- LoadFunctions
----------------------------------------------------------------
loadFunction :: HMODULE -> String -> (FunPtr a -> IO b) -> IO b
loadFunction dll name conv
  = withCAString name $ \c_name -> do
        proc <- unsupportedIfNull (missingFunction name)
                    $ c_GetProcAddress dll c_name
        conv $ castPtrToFunPtr proc

loadSystemFunction :: HMODULE -> String -> (FunPtr a -> IO b) -> IO b
loadSystemFunction dll name conv
  = withCAString name $ \c_name -> do
        -- Is failIfNull suitable or not?
        proc <- unsupportedIfNull (missingWin32Function name)
                    $ c_GetProcAddress dll c_name
        conv $ castPtrToFunPtr proc

loadLibrary' :: FilePath -> IO HINSTANCE
loadLibrary' name =
  withTString name $ \ c_name ->
  unsupportedIfNull (missingLibrary name) $ c_LoadLibrary c_name

withLoadFunction :: FilePath -> String -> (FunPtr a -> IO b) -> IO b
withLoadFunction dllname name conv =
  mask $ \restore -> do
    -- loadLibrry is better than c_getModuleHandle when load non-system library.
    dll    <- loadLibrary' dllname
    restore $ finally (loadFunction dll name conv) (freeLibrary dll)
{-
    result <- restore $
                catch (loadFunction dllname dll name conv)
                  (\e -> case e of
                           MissingFunction _ _ -> do freeLibrary dll
                                                     throwIO e
                           _ -> throwIO e)
    _      <- freeLibrary a
    return result
-}

withLoadSystemFunction :: String -> String -> (FunPtr a -> IO b) -> IO b
withLoadSystemFunction dllname name conv
  = bracket (getModuleHandle (Just dllname)) (\_ -> return ())
      $ \dll -> loadSystemFunction dll name conv

-- portable version
setSearchPathMode :: SearchPathModeFlags -> IO ()
setSearchPathMode flag =
  withLoadSystemFunction "Kernel32.dll" "SetSearchPathMode" $ \c_SetSearchPathMode ->
    failIfFalse_ "SetDllDirectory" $ convSetSearchPathMode c_SetSearchPathMode flag

type SearchPathModeFlags = DWORD
bASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE, bASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE, bASE_SEARCH_PATH_PERMANENT :: SearchPathModeFlags
bASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE = 0x00000001
bASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE = 0x00010000
bASE_SEARCH_PATH_PERMANENT = 0x00008000

foreign import WINDOWS_CCONV unsafe "dynamic" convSetSearchPathMode ::
   FunPtr (SearchPathModeFlags -> IO BOOL) -> (SearchPathModeFlags -> IO BOOL)
{-
-- non portable version.
setSearchPathMode :: SearchPathModeFlags -> IO ()
setSearchPathMode flag =
  failIfFalse_ "SetDllDirectory" $ c_SetSearchPathMode flag

foreign import WINDOWS_CCONV unsafe "windows.h SetSearchPathMode"
  c_SetSearchPathMode :: SearchPathModeFlags -> IO BOOL

{enum SearchPathModeFlags,
 , bASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE  = BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
 , bASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE = BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE
 , bASE_SEARCH_PATH_PERMANENT               = BASE_SEARCH_PATH_PERMANENT
 }
-}

setDllDirectory :: String -> IO ()
setDllDirectory name =
  withTString name $ \ c_name ->
  failIfFalse_ "SetDllDirectory" $ c_SetDllDirectory c_name

foreign import WINDOWS_CCONV unsafe "windows.h SetDllDirectoryW"
  c_SetDllDirectory :: LPTSTR -> IO BOOL