我正在尝试使用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
函数的源代码,但这对我没有帮助。
也许有一种更简单的方法可以做到这一点,我只是缺席了。
答案 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文档以了解在这些情况下会发生什么。