代码之家  ›  专栏  ›  技术社区  ›  Alasdair

获取haskell中的本地appdata文件夹

  •  3
  • Alasdair  · 技术社区  · 15 年前

    我正在尝试使用haskell以版本不可知的方式获取window的本地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
    

    我还尝试查看 getAppUserDataDirectory 在system.directory模块中运行,但这对我也没有帮助。

    也许有一个更简单的方法可以做到这一点,我只是想。

    2 回复  |  直到 15 年前
        1
  •  11
  •   robson3.14    15 年前

    如果你想携带,你 不应该 直接访问注册表。有一个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
    
        2
  •  0
  •   sth Alien    15 年前

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