{- - Copyright 2015 Egor Tensin - This file is licensed under the terms of the MIT License. - See LICENSE.txt for details. -} module Registry ( delValue , getString , hkcu , hklm , setString , KeyHandle ) where import Control.Exception ( bracket ) import Data.Maybe ( fromMaybe ) import Foreign.ForeignPtr ( withForeignPtr ) import Foreign.Marshal.Alloc ( alloca, allocaBytes ) import Foreign.Ptr ( castPtr, plusPtr ) import Foreign.Storable ( peek, poke, sizeOf ) import Graphics.Win32.Window ( sendMessage ) import System.IO.Error ( mkIOError, doesNotExistErrorType ) import System.Win32.Types import System.Win32.Registry newtype KeyHandle = KeyHandle HKEY getType :: HKEY -> String -> String -> IO (Maybe RegValueType) getType key subKeyPath valueName = bracket (regOpenKey key subKeyPath) regCloseKey $ \hKey -> withForeignPtr hKey $ \p_key -> withTString valueName $ \p_valueName -> alloca $ \p_type -> do ret <- c_RegQueryValueEx p_key p_valueName nullPtr p_type nullPtr nullPtr case ret of 0x0 -> do type_ <- peek p_type return $ Just type_ 0x2 -> return Nothing _ -> failWith "RegQueryValueEx" ret getString :: KeyHandle -> String -> String -> IO String getString (KeyHandle hKey) subKeyPath valueName = bracket (regOpenKey hKey subKeyPath) regCloseKey $ \hSubKey -> withForeignPtr hSubKey $ \p_key -> withTString valueName $ \p_valueName -> alloca $ \dataSizePtr -> do poke dataSizePtr 0 ret <- c_RegQueryValueEx p_key p_valueName nullPtr nullPtr nullPtr dataSizePtr case ret of 0x0 -> do dataSize <- peek dataSizePtr let newDataSize = dataSize + fromIntegral (sizeOf (undefined :: TCHAR)) poke dataSizePtr newDataSize allocaBytes (fromIntegral newDataSize) $ \dataPtr -> do poke (castPtr $ plusPtr dataPtr $ fromIntegral dataSize) '\0' failUnlessSuccess "RegQueryValueEx" $ c_RegQueryValueEx p_key p_valueName nullPtr nullPtr dataPtr dataSizePtr peekTString $ castPtr dataPtr 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) _ -> failWith "RegQueryValueEx" ret setString :: KeyHandle -> String -> String -> String -> IO () setString (KeyHandle hKey) subKeyPath valueName valueValue = bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> withTString valueValue $ \p_valueValue -> do type_ <- getType hKey subKeyPath valueName regSetValueEx subKey valueName (fromMaybe rEG_SZ type_) p_valueValue $ (length valueValue + 1) * sizeOf (undefined :: TCHAR) notifyEnvironmentUpdate notifyEnvironmentUpdate :: IO () notifyEnvironmentUpdate = withTString "Environment" $ \p_lparam -> do let wparam = 0 let lparam = fromIntegral $ castPtrToUINTPtr p_lparam let hwnd = castUINTPtrToPtr 0xffff _ <- sendMessage hwnd wM_SETTINGCHANGE wparam lparam return () where wM_SETTINGCHANGE = 0x1A delValue :: KeyHandle -> String -> String -> IO () delValue (KeyHandle hKey) subKeyPath valueName = bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> withForeignPtr subKey $ \subKeyPtr -> withTString valueName $ \p_valueName -> do ret <- c_RegDeleteValue subKeyPtr p_valueName notifyEnvironmentUpdate case ret of 0x0 -> return () 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) _ -> failWith "RegDeleteValue" ret hkcu :: KeyHandle hkcu = KeyHandle hKEY_CURRENT_USER hklm :: KeyHandle hklm = KeyHandle hKEY_LOCAL_MACHINE