#if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-} #endif ----------------------------------------------------------------------------- -- | -- Module : System.Win32.Registry -- Copyright : (c) Alastair Reid, 1997-2003 -- License : BSD-style (see the file libraries/base/LICENSE) -- -- Maintainer : Esa Ilari Vuokko -- Stability : provisional -- Portability : portable -- -- A collection of FFI declarations for accessing the Win32 registry. -- ----------------------------------------------------------------------------- module System.Win32.Registry ( module System.Win32.Registry ) where {- What's really on offer: ( regCloseKey -- :: HKEY -> IO () , regConnectRegistry -- :: Maybe String -> HKEY -> IO HKEY , regCreateKey -- :: HKEY -> String -> IO HKEY , regCreateKeyEx -- :: HKEY -> String -> String -- -> RegCreateOptions -> REGSAM -- -> Maybe LPSECURITY_ATTRIBUTES -- -> IO (HKEY, Bool) , regDeleteKey -- :: HKEY -> String -> IO () , regDeleteValue -- :: HKEY -> String -> IO () , regEnumKeys -- :: HKEY -> IO [String] , regEnumKey -- :: HKEY -> DWORD -> Addr -> DWORD -> IO String , regEnumKeyValue -- :: HKEY -> DWORD -> Addr -> DWORD -> Addr -> DWORD -> IO String , regFlushKey -- :: HKEY -> IO () , regLoadKey -- :: HKEY -> String -> String -> IO () , regNotifyChangeKeyValue -- :: HKEY -> Bool -> RegNotifyOptions -- -> HANDLE -> Bool -> IO () , regOpenKey -- :: HKEY -> String -> IO HKEY , regOpenKeyEx -- :: HKEY -> String -> REGSAM -> IO HKEY , regQueryInfoKey -- :: HKEY -> IO RegInfoKey , regQueryValue -- :: HKEY -> Maybe String -> IO String , regQueryValueKey -- :: HKEY -> Maybe String -> IO String , regQueryValueEx -- :: HKEY -> String -> Addr -> Int -> IO RegValueType , regReplaceKey -- :: HKEY -> String -> String -> String -> IO () , regRestoreKey -- :: HKEY -> String -> RegRestoreFlags -> IO () , regSaveKey -- :: HKEY -> String -> Maybe LPSECURITY_ATTRIBUTES -> IO () , regSetValue -- :: HKEY -> String -> String -> IO () , regSetValueEx -- :: HKEY -> String -> RegValueType -> LPTSTR -> Int -> IO () , regSetStringValue -- :: HKEY -> String -> String -> IO () , regUnloadKey -- :: HKEY -> String -> IO () ) where -} {- Registry API omissions: RegQueryMultipleValues() RegEnumKeyEx() -} import System.Win32.Time import System.Win32.Types import System.Win32.File import System.IO.Unsafe import Foreign hiding (unsafePerformIO) #include #{enum HKEY, (unsafePerformIO . newForeignHANDLE . castUINTToPtr) , hKEY_CLASSES_ROOT = (UINT)HKEY_CLASSES_ROOT , hKEY_CURRENT_CONFIG = (UINT)HKEY_CURRENT_CONFIG , hKEY_CURRENT_USER = (UINT)HKEY_CURRENT_USER , hKEY_LOCAL_MACHINE = (UINT)HKEY_LOCAL_MACHINE , hKEY_USERS = (UINT)HKEY_USERS } -- , PKEYERFORMANCE_DATA NT only -- , HKEY_DYN_DATA 95/98 only regCloseKey :: HKEY -> IO () regCloseKey key = withForeignPtr key $ \ p_key -> failUnlessSuccess "RegCloseKey" $ c_RegCloseKey p_key foreign import stdcall unsafe "windows.h RegCloseKey" c_RegCloseKey :: PKEY -> IO ErrCode -- Connects to a predefined registry handle on another computer. regConnectRegistry :: Maybe String -> HKEY -> IO HKEY regConnectRegistry mb_machine key = withForeignPtr key $ \ p_key -> maybeWith withTString mb_machine $ \ c_machine -> alloca $ \ p_out_key -> do failUnlessSuccess "RegConnectRegistry" $ c_RegConnectRegistry c_machine p_key p_out_key p_new_key <- peek p_out_key newForeignHANDLE p_new_key foreign import stdcall unsafe "windows.h RegConnectRegistryW" c_RegConnectRegistry :: LPCTSTR -> PKEY -> Ptr PKEY -> IO ErrCode regCreateKey :: HKEY -> String -> IO HKEY regCreateKey key subkey = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> alloca $ \ p_out_key -> do failUnlessSuccess "RegCreateKey" $ c_RegCreateKey p_key c_subkey p_out_key p_new_key <- peek p_out_key newForeignHANDLE p_new_key foreign import stdcall unsafe "windows.h RegCreateKeyW" c_RegCreateKey :: PKEY -> LPCTSTR -> Ptr PKEY -> IO ErrCode type RegCreateOptions = DWORD #{enum RegCreateOptions, , rEG_OPTION_NON_VOLATILE = REG_OPTION_NON_VOLATILE , rEG_OPTION_VOLATILE = REG_OPTION_VOLATILE } type REGSAM = #{type REGSAM} #{enum REGSAM, , kEY_ALL_ACCESS = KEY_ALL_ACCESS , kEY_CREATE_LINK = KEY_CREATE_LINK , kEY_CREATE_SUB_KEY = KEY_CREATE_SUB_KEY , kEY_ENUMERATE_SUB_KEYS = KEY_ENUMERATE_SUB_KEYS , kEY_EXECUTE = KEY_EXECUTE , kEY_NOTIFY = KEY_NOTIFY , kEY_QUERY_VALUE = KEY_QUERY_VALUE , kEY_READ = KEY_READ , kEY_SET_VALUE = KEY_SET_VALUE , kEY_WRITE = KEY_WRITE } regCreateKeyEx :: HKEY -> String -> String -> RegCreateOptions -> REGSAM -> Maybe LPSECURITY_ATTRIBUTES -> IO (HKEY, Bool) regCreateKeyEx key subkey cls opts sam mb_attr = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> withTString cls $ \ c_cls -> alloca $ \ p_res -> alloca $ \ p_disp -> do failUnlessSuccess "RegCreateKeyEx" $ c_RegCreateKeyEx p_key c_subkey 0 c_cls opts sam (maybePtr mb_attr) p_res p_disp p_out_key <- peek p_res out_key <- newForeignHANDLE p_out_key disp <- peek p_disp return (out_key, disp == #{const REG_CREATED_NEW_KEY}) foreign import stdcall unsafe "windows.h RegCreateKeyExW" c_RegCreateKeyEx :: PKEY -> LPCTSTR -> DWORD -> LPCTSTR -> RegCreateOptions -> REGSAM -> LPSECURITY_ATTRIBUTES -> Ptr PKEY -> Ptr DWORD -> IO ErrCode regDeleteKey :: HKEY -> String -> IO () regDeleteKey key subkey = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> failUnlessSuccess "RegDeleteKey" $ c_RegDeleteKey p_key c_subkey foreign import stdcall unsafe "windows.h RegDeleteKeyW" c_RegDeleteKey :: PKEY -> LPCTSTR -> IO ErrCode regDeleteValue :: HKEY -> String -> IO () regDeleteValue key name = withForeignPtr key $ \ p_key -> withTString name $ \ c_name -> failUnlessSuccess "RegDeleteValue" $ c_RegDeleteValue p_key c_name foreign import stdcall unsafe "windows.h RegDeleteValueW" c_RegDeleteValue :: PKEY -> LPCTSTR -> IO ErrCode -- XXX Not 100% sure this is right, but I think it is. -- Surely this function already exists somewhere? mallocWideChars :: Int -> IO (Ptr a) mallocWideChars i = mallocBytes (4 * i) regEnumKeys :: HKEY -> IO [String] regEnumKeys hkey = do hinfo <- regQueryInfoKey hkey let buflen = 1+max_subkey_len hinfo buf <- mallocWideChars (fromIntegral buflen) ls <- go 0 buf buflen free buf return ls where go n buf buflen = do (v,flg) <- regEnumKey hkey n buf buflen if flg /= 0 then return [] else do vs <- go (n+1) buf buflen return (v:vs) regEnumKeyVals :: HKEY -> IO [(String,String,RegValueType)] regEnumKeyVals hkey = do hinfo <- regQueryInfoKey hkey let nmlen = 1+max_value_name_len hinfo -- add spc for terminating NUL. let vallen = 1+max_value_len hinfo nmbuf <- mallocWideChars (fromIntegral nmlen) valbuf <- mallocWideChars (fromIntegral vallen) ls <- go 0 nmbuf nmlen valbuf vallen free nmbuf free valbuf return ls where go n nmbuf nmlen valbuf vallen = do (ty,nm,flg) <- regEnumValue hkey n nmbuf nmlen valbuf vallen if flg /= 0 then return [] else do val <- case ty of x | x == rEG_SZ -> peekTString (castPtr valbuf) | x == rEG_DWORD -> peekElemOff (castPtr valbuf) 0 >>= \ v -> return (show (v :: DWORD)) | otherwise -> return "<>" vs <- go (n+1) nmbuf nmlen valbuf vallen return ((nm,val,ty):vs) -- It's up to the programmer to ensure that a large enough -- buffer is passed in here. regEnumKey :: HKEY -> DWORD -> LPTSTR -> DWORD -> IO (String, Int) regEnumKey key index c_name len = withForeignPtr key $ \ p_key -> do no_more <- failUnlessSuccessOr eRROR_NO_MORE_ITEMS "RegEnumKey" $ c_RegEnumKey p_key index c_name len str <- peekTString c_name return (str, fromEnum no_more) foreign import stdcall unsafe "windows.h RegEnumKeyW" c_RegEnumKey :: PKEY -> DWORD -> LPTSTR -> DWORD -> IO ErrCode regEnumValue :: HKEY -> DWORD -> LPTSTR -> DWORD -> LPBYTE -> DWORD -> IO (RegValueType, String, Int) regEnumValue key index name name_len value value_len = withForeignPtr key $ \ p_key -> with name_len $ \ p_name_len -> with value_len $ \ p_value_len -> alloca $ \ p_reg_ty -> do no_more <- failUnlessSuccessOr eRROR_NO_MORE_ITEMS "RegEnumValue" $ c_RegEnumValue p_key index name p_name_len nullPtr p_reg_ty value p_value_len reg_ty <- peek p_reg_ty str <- peekTString name return (reg_ty, str, fromEnum no_more) foreign import stdcall unsafe "windows.h RegEnumValueW" c_RegEnumValue :: PKEY -> DWORD -> LPTSTR -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> LPBYTE -> Ptr DWORD -> IO ErrCode eRROR_NO_MORE_ITEMS :: ErrCode eRROR_NO_MORE_ITEMS = #{const ERROR_NO_MORE_ITEMS} regFlushKey :: HKEY -> IO () regFlushKey key = withForeignPtr key $ \ p_key -> failUnlessSuccess "RegFlushKey" $ c_RegFlushKey p_key foreign import stdcall unsafe "windows.h RegFlushKey" c_RegFlushKey :: PKEY -> IO ErrCode -- ifdef FOR_WINDOWS_NT -- RegGetKeySecurity :: HKEY -> SECURITY_INFORMATION -> IO SECURITY_DESCRIPTION -- endif regLoadKey :: HKEY -> String -> String -> IO () regLoadKey key subkey file = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> withTString file $ \ c_file -> failUnlessSuccess "RegLoadKey" $ c_RegLoadKey p_key c_subkey c_file foreign import stdcall unsafe "windows.h RegLoadKeyW" c_RegLoadKey :: PKEY -> LPCTSTR -> LPCTSTR -> IO ErrCode -- ifdef FOR_WINDOWS_NT type RegNotifyOptions = DWORD #{enum RegNotifyOptions, , rEG_NOTIFY_CHANGE_NAME = REG_NOTIFY_CHANGE_NAME , rEG_NOTIFY_CHANGE_ATTRIBUTES = REG_NOTIFY_CHANGE_ATTRIBUTES , rEG_NOTIFY_CHANGE_LAST_SET = REG_NOTIFY_CHANGE_LAST_SET , rEG_NOTIFY_CHANGE_SECURITY = REG_NOTIFY_CHANGE_SECURITY } regNotifyChangeKeyValue :: HKEY -> Bool -> RegNotifyOptions -> HANDLE -> Bool -> IO () regNotifyChangeKeyValue key watch notifyFilter event async = withForeignPtr key $ \ p_key -> failUnlessSuccess "RegNotifyChangeKeyValue" $ c_RegNotifyChangeKeyValue p_key watch notifyFilter event async foreign import stdcall unsafe "windows.h RegNotifyChangeKeyValue" c_RegNotifyChangeKeyValue :: PKEY -> Bool -> RegNotifyOptions -> HANDLE -> Bool -> IO ErrCode -- endif -- for Win 3.x compatibility, use RegOpenKeyEx instead. regOpenKey :: HKEY -> String -> IO HKEY regOpenKey key subkey = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> alloca $ \ p_res -> do failUnlessSuccess "RegOpenKey" $ c_RegOpenKey p_key c_subkey p_res p_res_key <- peek p_res newForeignHANDLE p_res_key foreign import stdcall unsafe "windows.h RegOpenKeyW" c_RegOpenKey :: PKEY -> LPCTSTR -> Ptr PKEY -> IO ErrCode regOpenKeyEx :: HKEY -> String -> REGSAM -> IO HKEY regOpenKeyEx key subkey sam = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> alloca $ \ p_res -> do failUnlessSuccess "RegOpenKeyEx" $ c_RegOpenKeyEx p_key c_subkey 0 sam p_res p_res_key <- peek p_res newForeignHANDLE p_res_key foreign import stdcall unsafe "windows.h RegOpenKeyExW" c_RegOpenKeyEx :: PKEY -> LPCTSTR -> DWORD -> REGSAM -> Ptr PKEY -> IO ErrCode data RegInfoKey = RegInfoKey { class_string :: String, class_id :: Int, subkeys :: Word32, max_subkey_len :: Word32, max_class_len :: Word32, values :: Word32, max_value_name_len :: Word32, max_value_len :: Word32, sec_len :: Int, lastWrite_lo :: Word32, lastWrite_hi :: Word32 } regQueryInfoKey :: HKEY -> IO RegInfoKey regQueryInfoKey key = withForeignPtr key $ \ p_key -> allocaBytes 100 $ \ c_class_string -> alloca $ \ p_class_id -> alloca $ \ p_subkeys -> alloca $ \ p_max_subkey_len -> alloca $ \ p_max_class_len -> alloca $ \ p_values -> alloca $ \ p_max_value_name_len -> alloca $ \ p_max_value_len -> alloca $ \ p_sec_len -> allocaBytes (#{size FILETIME}) $ \ p_lastWrite -> do failUnlessSuccess "RegQueryInfoKey" $ c_RegQueryInfoKey p_key c_class_string p_class_id nullPtr p_subkeys p_max_subkey_len p_max_class_len p_values p_max_value_name_len p_max_value_len p_sec_len p_lastWrite class_string <- peekTString c_class_string class_id <- peek p_class_id subkeys <- peek p_subkeys max_subkey_len <- peek p_max_subkey_len max_class_len <- peek p_max_class_len values <- peek p_values max_value_name_len <- peek p_max_value_name_len max_value_len <- peek p_max_value_len sec_len <- peek p_sec_len lastWrite_lo <- #{peek FILETIME,dwLowDateTime} p_lastWrite lastWrite_hi <- #{peek FILETIME,dwHighDateTime} p_lastWrite return $ RegInfoKey { class_string = class_string , class_id = fromIntegral class_id , subkeys = subkeys , max_subkey_len = max_subkey_len , max_class_len = max_class_len , values = values , max_value_name_len = max_value_name_len , max_value_len = max_value_len , sec_len = fromIntegral sec_len , lastWrite_lo = lastWrite_lo , lastWrite_hi = lastWrite_hi } foreign import stdcall unsafe "windows.h RegQueryInfoKeyW" c_RegQueryInfoKey :: PKEY -> LPTSTR -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr FILETIME -> IO ErrCode -- RegQueryMultipleValues :: HKEY -> IO ([VALENT],String) -- RegQueryValue() isn't really that, it just allows you to -- get at the default values of keys, so we provide our own -- (and better!) version of it. If you want RegQueryValue()s -- behaviour, use regQueryValueKey. regQueryValueKey :: HKEY -> Maybe String -> IO String regQueryValueKey key mb_subkey = withForeignPtr key $ \ p_key -> maybeWith withTString mb_subkey $ \ c_subkey -> alloca $ \ p_value_len -> do failUnlessSuccess "RegQueryValue" $ c_RegQueryValue p_key c_subkey nullPtr p_value_len value_len <- peek p_value_len allocaArray0 (fromIntegral value_len) $ \ c_value -> do failUnlessSuccess "RegQueryValue" $ c_RegQueryValue p_key c_subkey c_value p_value_len peekTString c_value foreign import stdcall unsafe "windows.h RegQueryValueW" c_RegQueryValue :: PKEY -> LPCTSTR -> LPTSTR -> Ptr LONG -> IO ErrCode regQueryValue :: HKEY -> Maybe String -> IO String regQueryValue key mb_subkey = withForeignPtr key $ \ p_key -> maybeWith withTString mb_subkey $ \ c_subkey -> alloca $ \ p_ty -> alloca $ \ p_value_len -> do failUnlessSuccess "RegQueryValue" $ c_RegQueryValueEx p_key c_subkey nullPtr p_ty nullPtr p_value_len ty <- peek p_ty failUnlessSuccess "RegQueryValue" $ return (if ty == rEG_SZ then 0 else 1) value_len <- peek p_value_len allocaArray0 (fromIntegral value_len) $ \ c_value -> do failUnlessSuccess "RegQueryValue" $ c_RegQueryValueEx p_key c_subkey nullPtr p_ty c_value p_value_len peekTString (castPtr c_value) regQueryValueEx :: HKEY -> String -> LPBYTE -> Int -> IO RegValueType regQueryValueEx key name value value_len = withForeignPtr key $ \ p_key -> withTString name $ \ c_name -> alloca $ \ p_ty -> with (fromIntegral value_len) $ \ p_value_len -> do failUnlessSuccess "RegQueryValueEx" $ c_RegQueryValueEx p_key c_name nullPtr p_ty value p_value_len peek p_ty foreign import stdcall unsafe "windows.h RegQueryValueExW" c_RegQueryValueEx :: PKEY -> LPCTSTR -> Ptr DWORD -> Ptr DWORD -> LPBYTE -> Ptr DWORD -> IO ErrCode regReplaceKey :: HKEY -> String -> String -> String -> IO () regReplaceKey key subkey newfile oldfile = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> withTString newfile $ \ c_newfile -> withTString oldfile $ \ c_oldfile -> failUnlessSuccess "RegReplaceKey" $ c_RegReplaceKey p_key c_subkey c_newfile c_oldfile foreign import stdcall unsafe "windows.h RegReplaceKeyW" c_RegReplaceKey :: PKEY -> LPCTSTR -> LPCTSTR -> LPCTSTR -> IO ErrCode type RegRestoreFlags = DWORD #{enum RegRestoreFlags, , rEG_WHOLE_HIVE_VOLATILE = REG_WHOLE_HIVE_VOLATILE , rEG_REFRESH_HIVE = REG_REFRESH_HIVE , rEG_NO_LAZY_FLUSH = REG_NO_LAZY_FLUSH } regRestoreKey :: HKEY -> String -> RegRestoreFlags -> IO () regRestoreKey key file flags = withForeignPtr key $ \ p_key -> withTString file $ \ c_file -> failUnlessSuccess "RegRestoreKey" $ c_RegRestoreKey p_key c_file flags foreign import stdcall unsafe "windows.h RegRestoreKeyW" c_RegRestoreKey :: PKEY -> LPCTSTR -> RegRestoreFlags -> IO ErrCode regSaveKey :: HKEY -> String -> Maybe LPSECURITY_ATTRIBUTES -> IO () regSaveKey key file mb_attr = withForeignPtr key $ \ p_key -> withTString file $ \ c_file -> failUnlessSuccess "RegSaveKey" $ c_RegSaveKey p_key c_file (maybePtr mb_attr) foreign import stdcall unsafe "windows.h RegSaveKeyW" c_RegSaveKey :: PKEY -> LPCTSTR -> LPSECURITY_ATTRIBUTES -> IO ErrCode -- ifdef FOR_WINDOWS_NT -- RegSetKeySecurity :: HKEY -> SECURITY_INFORMATION -> SECURITY_DESCRIPTOR -> IO () -- endif -- 3.1 compat. - only allows storage of REG_SZ values. regSetValue :: HKEY -> String -> String -> IO () regSetValue key subkey value = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> withTStringLen value $ \ (c_value, value_len) -> failUnlessSuccess "RegSetValue" $ c_RegSetValue p_key c_subkey rEG_SZ c_value value_len foreign import stdcall unsafe "windows.h RegSetValueW" c_RegSetValue :: PKEY -> LPCTSTR -> DWORD -> LPCTSTR -> Int -> IO ErrCode type RegValueType = DWORD #{enum RegValueType, , rEG_BINARY = REG_BINARY , rEG_DWORD = REG_DWORD , rEG_DWORD_LITTLE_ENDIAN = REG_DWORD_LITTLE_ENDIAN , rEG_DWORD_BIG_ENDIAN = REG_DWORD_BIG_ENDIAN , rEG_EXPAND_SZ = REG_EXPAND_SZ , rEG_LINK = REG_LINK , rEG_MULTI_SZ = REG_MULTI_SZ , rEG_NONE = REG_NONE , rEG_RESOURCE_LIST = REG_RESOURCE_LIST , rEG_SZ = REG_SZ } -- regSetValueEx has a somewhat wieldly interface if all you want to do is -- add a string value (a Common Thing to want to do), so we support this -- specially: regSetStringValue :: HKEY -> String -> String -> IO () regSetStringValue hk key val = withTString val $ \ v -> regSetValueEx hk key rEG_SZ v (length val * sizeOf (undefined::TCHAR)) regSetValueEx :: HKEY -> String -> RegValueType -> LPTSTR -> Int -> IO () regSetValueEx key subkey ty value value_len = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> failUnlessSuccess "RegSetValueEx" $ c_RegSetValueEx p_key c_subkey 0 ty value value_len foreign import stdcall unsafe "windows.h RegSetValueExW" c_RegSetValueEx :: PKEY -> LPCTSTR -> DWORD -> RegValueType -> LPTSTR -> Int -> IO ErrCode regUnLoadKey :: HKEY -> String -> IO () regUnLoadKey key subkey = withForeignPtr key $ \ p_key -> withTString subkey $ \ c_subkey -> failUnlessSuccess "RegUnLoadKey" $ c_RegUnLoadKey p_key c_subkey foreign import stdcall unsafe "windows.h RegUnLoadKeyW" c_RegUnLoadKey :: PKEY -> LPCTSTR -> IO ErrCode