2009-08-23 5 views
3

하스켈을 사용하여 버전에 관계없이 Window AppData 폴더의 위치를 ​​얻으려고하고 있는데 문제가 있습니다. System.Win32.Registry 라이브러리를 사용해 보았습니다. (시행 착오 후) 아래 코드를 얻을 수 있었지만, regQueryValueEx 또는 다른 함수를 사용하는 방법을 알 수 없었습니다. 내가 필요한 가치. 하스켈에서 로컬 AppData 폴더 받기

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 함수에 대한 소스 코드를보고했는데, 그 중 하나가 나에게 도움이되지 않았다.

아마도 내가 누락 된 쉬운 방법이 있습니다.

답변

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 
0

유용한 형식으로 레지스트리에서 값을 읽으려면 하스켈과 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 

잘 모르겠어요 모든 오류의 경우 제대로 처리하는 경우 (같은 전달 된 버퍼는 작은이었다 경우), 그래서 당신은 창을 확인 할 수 있습니다 이 경우 어떤 일이 발생하는지 보려면 docs.

+0

대단히 감사합니다. – Alasdair

+0

문서화 된 방법이 아니며 작동하는 Windows가 불분명합니다. 그것은 Alasdairn이 이미 가지고 있던 것과 가장 가까운 것이지만, API 솔루션이 더 좋습니다. – MSalters

+0

나는 Alasdair가 이미 가지고 있었고 다른 Api 호출을 찾지 않았다. 어쨌든, 별도의 API를 사용하지 않는 다른 레지스트리 값을 읽으려는 다른 사람들에게 유용하기 때문에 삭제하지 않겠습니다. – sth

관련 문제