haskell / win32

Haskell support for the Win32 API
http://hackage.haskell.org/package/Win32
Other
97 stars 61 forks source link

Can't retrieve registry value size #230

Open hverstoep opened 7 months ago

hverstoep commented 7 months ago

I can't retrieve registry value size. This is needed to be able to provide a buffer of the right size. See function here: https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa

Current Behavior

We can specify the buffer size (Int):

regQueryValueEx :: HKEY -> String -> LPBYTE -> Int -> IO RegValueType
regQueryValueEx key name value value_len =
  withForeignPtr key $ \ p_key ->
  withTString name $ \ c_name ->
  alloca $ \ p_ty ->
  with (fromIntegral value_len) $ \ p_value_len -> do
  failUnlessSuccess "RegQueryValueEx" $
    c_RegQueryValueEx p_key c_name nullPtr p_ty value p_value_len
  peek p_ty
foreign import WINDOWS_CCONV unsafe "windows.h RegQueryValueExW"
  c_RegQueryValueEx :: PKEY -> LPCTSTR -> Ptr DWORD -> Ptr DWORD -> LPBYTE -> Ptr DWORD -> IO ErrCode

But it isn't returned. I need to call the function once with 0 to get the required buffer size, the allocate the buffer, and call the function again. Perhaps something like:

regQueryValueEx' :: HKEY -> String -> LPBYTE -> Int -> IO (Int, RegValueType)
regQueryValueEx' key name value value_len =
  withForeignPtr key $ \ p_key ->
  withTString name $ \ c_name ->
  alloca $ \ p_ty ->
  with (fromIntegral value_len) $ \ p_value_len -> do
  failUnlessSuccess "RegQueryValueEx" $
    c_RegQueryValueEx p_key c_name nullPtr p_ty value p_value_len
  (,) <$> (fromIntegral <$> peek p_value_len) <*> peek p_ty
foreign import ccall unsafe "windows.h RegQueryValueExW"
  c_RegQueryValueEx :: PKEY -> LPCTSTR -> Ptr DWORD -> Ptr DWORD -> LPBYTE -> Ptr DWORD -> IO ErrCode

Your Environment

Mistuke commented 6 months ago

Hi, thanks for the report. I'll take a look tomorrow evening.

Mistuke commented 6 months ago

Sorry for the delay, was caught up in some work.

Hmm maybe we should just expose the size parameter as a pointer? So maybe just

regQueryValueEx' :: HKEY -> String -> LPBYTE -> Ptr Int -> IO RegValueType

since you have to create value anyway, but maybe this is a less natural fit.

I think we should avoid the deference unless the results is ERROR_MORE_DATA and so leaving it up to the caller seems more natural.