如何实现 EnumSystemLocalesEx 与 Haskell FFI 的绑定?
How to implement EnumSystemLocalesEx binding with Haskell FFI?
我正在尝试实施 Haskell 绑定到 Win32 API 的 EnumSystemLocalesEx
function,但仅取得了部分成功。我想知道为什么以及如何解决问题。
我的绑定看起来像这样(需要从 Win32
包的模块导入):
type LOCALE_ENUMPROCEX = LPWSTR -> DWORD -> LPARAM -> IO BOOL
foreign import WINDOWS_CCONV "wrapper"
mkLOCALE_ENUMPROCEX :: LOCALE_ENUMPROCEX -> IO (FunPtr LOCALE_ENUMPROCEX)
enumSystemLocalesEx :: LOCALE_ENUMPROCEX -> DWORD -> LPARAM -> IO ()
enumSystemLocalesEx callback dwFlags lParam = do
c_callback <- mkLOCALE_ENUMPROCEX callback
failIfFalse_ "EnumSystemLocalesEx" $
c_EnumSystemLocalesEx c_callback dwFlags lParam nullPtr
freeHaskellFunPtr c_callback
foreign import WINDOWS_CCONV unsafe "windows.h EnumSystemLocalesEx"
c_EnumSystemLocalesEx :: (FunPtr LOCALE_ENUMPROCEX)
-> DWORD
-> LPARAM
-> LPVOID
-> IO Bool
我的简单测试如下所示:
main :: IO ()
main = do
enumSystemLocalesEx callback 1 0
callback :: LOCALE_ENUMPROCEX
callback c_locale _ _ = do
locale <- peekTString c_locale
putStrLn $ "locale is: " <> show locale
pure True
部分成功如下。编译和 运行 测试可执行文件按字母顺序生成大约 120 多行输出,然后可执行文件 'hangs' 不再产生输出,也不会 return - 下面摘录(使用 en-ER
是最后一个输出;显然有比这更多的系统语言环境):
locale is: ""
locale is: "aa"
locale is: "aa-DJ"
locale is: "aa-ER"
locale is: "aa-ET"
...
locale is: "en-CY"
locale is: "en-DE"
locale is: "en-DK"
locale is: "en-DM"
locale is: "en-ER"
好像某种'capacity'在某处用完了。
编辑:如果我将输出更改为 putStrLn $ "The locale to be displayed is: " <> show locale
(更多字符),它会更早 'hangs'(在 "ebu"
)。如果我将它更改为 print locale
(更少的字符),它会在 'hangs' 之后(在 "en-MH"
)。如果我将它更改为无输出 (callback _ _ _ = pure True
),它仍然是 'hangs',所以问题不是输出本身。此外,命令提示符中的行为与 Windows 终端中的行为相同。我正在使用 Windows 10 版本 2004 并使用 stack
、解析器 lts-16.12
(GHC 8.8.4) 构建。
我已经在与您相同的环境中测试了示例,但我收到错误消息“schedule: re-entered unsafely.”:
如果我删除关键字 unsafe
,则示例适用于我:
这是我使用的示例:
import System.Win32.Types
import Foreign.Ptr
import Foreign.C
type LOCALE_ENUMPROCEX = LPWSTR -> DWORD -> LPARAM -> IO BOOL
foreign import ccall "wrapper"
mkLOCALE_ENUMPROCEX :: LOCALE_ENUMPROCEX -> IO (FunPtr LOCALE_ENUMPROCEX)
enumSystemLocalesEx :: LOCALE_ENUMPROCEX -> DWORD -> LPARAM -> IO ()
enumSystemLocalesEx callback dwFlags lParam = do
c_callback <- mkLOCALE_ENUMPROCEX callback
failIfFalse_ "EnumSystemLocalesEx" $
c_EnumSystemLocalesEx c_callback dwFlags lParam nullPtr
freeHaskellFunPtr c_callback
foreign import ccall "windows.h EnumSystemLocalesEx"
c_EnumSystemLocalesEx :: (FunPtr LOCALE_ENUMPROCEX)
-> DWORD
-> LPARAM
-> LPVOID
-> IO Bool
main :: IO ()
main = do
enumSystemLocalesEx callback 1 0
putStrLn "Succeed"
callback :: LOCALE_ENUMPROCEX
callback c_locale _ _ = do
locale <- peekTString c_locale
putStrLn $ "locale is: " <> show locale
pure True
似乎 如果您使用不安全关键字注释外部导入声明,这向编译器表明该调用不会直接或间接调用另一个 Haskell 函数。 查看 中的答案了解详情。
我正在尝试实施 Haskell 绑定到 Win32 API 的 EnumSystemLocalesEx
function,但仅取得了部分成功。我想知道为什么以及如何解决问题。
我的绑定看起来像这样(需要从 Win32
包的模块导入):
type LOCALE_ENUMPROCEX = LPWSTR -> DWORD -> LPARAM -> IO BOOL
foreign import WINDOWS_CCONV "wrapper"
mkLOCALE_ENUMPROCEX :: LOCALE_ENUMPROCEX -> IO (FunPtr LOCALE_ENUMPROCEX)
enumSystemLocalesEx :: LOCALE_ENUMPROCEX -> DWORD -> LPARAM -> IO ()
enumSystemLocalesEx callback dwFlags lParam = do
c_callback <- mkLOCALE_ENUMPROCEX callback
failIfFalse_ "EnumSystemLocalesEx" $
c_EnumSystemLocalesEx c_callback dwFlags lParam nullPtr
freeHaskellFunPtr c_callback
foreign import WINDOWS_CCONV unsafe "windows.h EnumSystemLocalesEx"
c_EnumSystemLocalesEx :: (FunPtr LOCALE_ENUMPROCEX)
-> DWORD
-> LPARAM
-> LPVOID
-> IO Bool
我的简单测试如下所示:
main :: IO ()
main = do
enumSystemLocalesEx callback 1 0
callback :: LOCALE_ENUMPROCEX
callback c_locale _ _ = do
locale <- peekTString c_locale
putStrLn $ "locale is: " <> show locale
pure True
部分成功如下。编译和 运行 测试可执行文件按字母顺序生成大约 120 多行输出,然后可执行文件 'hangs' 不再产生输出,也不会 return - 下面摘录(使用 en-ER
是最后一个输出;显然有比这更多的系统语言环境):
locale is: ""
locale is: "aa"
locale is: "aa-DJ"
locale is: "aa-ER"
locale is: "aa-ET"
...
locale is: "en-CY"
locale is: "en-DE"
locale is: "en-DK"
locale is: "en-DM"
locale is: "en-ER"
好像某种'capacity'在某处用完了。
编辑:如果我将输出更改为 putStrLn $ "The locale to be displayed is: " <> show locale
(更多字符),它会更早 'hangs'(在 "ebu"
)。如果我将它更改为 print locale
(更少的字符),它会在 'hangs' 之后(在 "en-MH"
)。如果我将它更改为无输出 (callback _ _ _ = pure True
),它仍然是 'hangs',所以问题不是输出本身。此外,命令提示符中的行为与 Windows 终端中的行为相同。我正在使用 Windows 10 版本 2004 并使用 stack
、解析器 lts-16.12
(GHC 8.8.4) 构建。
我已经在与您相同的环境中测试了示例,但我收到错误消息“schedule: re-entered unsafely.”:
如果我删除关键字 unsafe
,则示例适用于我:
这是我使用的示例:
import System.Win32.Types
import Foreign.Ptr
import Foreign.C
type LOCALE_ENUMPROCEX = LPWSTR -> DWORD -> LPARAM -> IO BOOL
foreign import ccall "wrapper"
mkLOCALE_ENUMPROCEX :: LOCALE_ENUMPROCEX -> IO (FunPtr LOCALE_ENUMPROCEX)
enumSystemLocalesEx :: LOCALE_ENUMPROCEX -> DWORD -> LPARAM -> IO ()
enumSystemLocalesEx callback dwFlags lParam = do
c_callback <- mkLOCALE_ENUMPROCEX callback
failIfFalse_ "EnumSystemLocalesEx" $
c_EnumSystemLocalesEx c_callback dwFlags lParam nullPtr
freeHaskellFunPtr c_callback
foreign import ccall "windows.h EnumSystemLocalesEx"
c_EnumSystemLocalesEx :: (FunPtr LOCALE_ENUMPROCEX)
-> DWORD
-> LPARAM
-> LPVOID
-> IO Bool
main :: IO ()
main = do
enumSystemLocalesEx callback 1 0
putStrLn "Succeed"
callback :: LOCALE_ENUMPROCEX
callback c_locale _ _ = do
locale <- peekTString c_locale
putStrLn $ "locale is: " <> show locale
pure True
似乎 如果您使用不安全关键字注释外部导入声明,这向编译器表明该调用不会直接或间接调用另一个 Haskell 函数。 查看