Чтобы прочитать значения из реестра в полезном формате, требуется довольно много кода для преобразования между типами Haskell и C. И то, что рассматриваемые значения обычно имеют тип REG_EXPAND_SZ
, также не помогает. Так что это не красиво, но это работает для меня:
{-# LANGUAGE ForeignFunctionInterface #-}
import System.Win32.Types
import System.Win32.Registry
import Foreign.Ptr (castPtr)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.C.String (peekCWString, withCWString)
import Control.Exception (bracket, throwIO)
-- // parse a string from a registry value of certain type
parseRegString :: RegValueType -> LPBYTE -> IO String
parseRegString ty mem
| ty == rEG_SZ = peekCWString (castPtr mem)
| ty == rEG_EXPAND_SZ = peekCWString (castPtr mem) >>=
expandEnvironmentStrings
| otherwise = ioError (userError "Invalid registry value type")
-- // FFI import of the ExpandEnvironmentStrings function needed
-- // to make use of the registry values
expandEnvironmentStrings :: String -> IO String
expandEnvironmentStrings toexpand =
withCWString toexpand $ \input ->
allocaBytes 512 $ \output ->
do c_ExpandEnvironmentStrings input output 256
peekCWString output
foreign import stdcall unsafe "windows.h ExpandEnvironmentStringsW"
c_ExpandEnvironmentStrings :: LPCTSTR -> LPTSTR -> DWORD -> IO DWORD
-- // open the registry key
userShellFolders :: IO HKEY
userShellFolders = regOpenKeyEx hKEY_CURRENT_USER
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"
kEY_QUERY_VALUE
-- // read the actual value
localAppData :: IO String
localAppData =
bracket userShellFolders regCloseKey $ \usfkey ->
allocaBytes 512 $ \mem ->
do ty <- regQueryValueEx usfkey "Local AppData" mem 512
parseRegString ty mem
main = localAppData >>= print
Я не уверен, что все случаи ошибок обрабатываются правильно (например, если переданный буфер был маленьким), поэтому вы можете проверить документацию Windows, чтобы увидеть, что происходит в этих случаях.