Getting the Local AppData folder in Haskell
haskell, registry, windows
Solution
If you want portability, you shouldn't access registry directly. There is an API function to get special folders: SHGetFolderPath. You can call it thus:
{-# 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
Problem
I'm trying to get the location of Window's Local AppData folder in a version-agnostic manner using Haskell, and I'm having a bit of trouble doing so. I've tried using the System.Win32.Registry library, and I was able to get the code below (after some trial and error), but I wasn't able to figure out how to use the `regQueryValueEx` or any other function to get the value I need. ``` 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 ``` I also tried looking at the source code for the `getAppUserDataDirectory` function in the System.Directory module, but that didn't help me either. Maybe there's an easier way to do this that I'm just missing.