获取Haskell中的本地AppData文件夹

时间:2009-08-23 00:18:04

标签: windows haskell registry

我正在尝试使用Haskell以版本无关的方式获取Window的Local AppData文件夹的位置,我在这方面遇到了一些麻烦。我已经尝试使用System.Win32.Registry库,我能够得到下面的代码(经过一些试验和错误),但我无法弄清楚如何使用regQueryValueEx或任何其他函数来获取我需要的值。

import System.Win32.Types
import System.Win32.Registry

userShellFolders :: IO HKEY
userShellFolders = regOpenKeyEx hKEY_CURRENT_USER "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\" kEY_QUERY_VALUE

我也尝试查看System.Directory模块中getAppUserDataDirectory函数的源代码,但这对我没有帮助。

也许有一种更简单的方法可以做到这一点,我只是缺席了。

2 个答案:

答案 0 :(得分:11)

如果您想要可移植性,不应直接访问注册表。有一个API函数 获取特殊文件夹:SHGetFolderPath。你可以这样称呼它:

{-# LANGUAGE ForeignFunctionInterface #-}
import System.Win32.Types
import Graphics.Win32.GDI.Types
import Foreign.C.String
import Foreign.Marshal.Array

foreign import stdcall unsafe "SHGetFolderPathW"
    cSHGetFolderPathW :: HWND -> INT -> HANDLE -> DWORD -> CWString -> IO LONG

maxPath = 260
cSIDL_LOCAL_APPDATA = 0x001c -- //see file ShlObj.h in MS Platform SDK for other CSIDL constants

getShellFolder :: INT -> IO String
getShellFolder csidl = allocaArray0 maxPath $ \path -> do
    cSHGetFolderPathW nullHANDLE csidl nullHANDLE 0 path
    peekCWString path

main = getShellFolder cSIDL_LOCAL_APPDATA >>= putStrLn

答案 1 :(得分:0)

要以有用的格式从注册表中读取值,需要在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文档以了解在这些情况下会发生什么。