我试图编写一些win32包中未包含的win32 API函数的绑定,但遇到了一些困难。在下面的代码中,EnumWindows和GetWindow的绑定工作正常,但GetWindowText和GetWindowTextLength的绑定不能:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.Ptr
import Graphics.Win32.GDI.Types (HWND)
import System.Win32.Types (ptrToMaybe)
import Foreign.C
import Foreign.Marshal.Alloc (free)
import Control.Applicative ((<$>))
gW_CHILD = 5::CInt
getWindow :: HWND -> CInt -> IO (Maybe HWND)
getWindow hwnd cint = ptrToMaybe <$> (c_getWindow hwnd cint)
foreign import stdcall "windows.h GetWindow"
c_getWindow :: HWND -> CInt -> IO HWND
foreign import stdcall "windows.h EnumWindows"
enumWindows :: (FunPtr (HWND -> Ptr b -> IO a)) -> CInt -> IO CInt
foreign import stdcall "windows.h GetWindowText"
getWindowText :: HWND -> CString -> CInt -> IO CInt
foreign import stdcall "windows.h GetWindowTextLength"
getWindowTextLength :: HWND -> IO CInt
foreign import ccall "wrapper"
wrapEnumWindowsProc :: (HWND -> Ptr a -> IO CInt) -> IO (FunPtr (HWND -> Ptr a-> IO CInt))
findFirstNamedChildWindow :: HWND -> Ptr a -> IO CInt
findFirstNamedChildWindow hwnd _ = do
mchild <- getWindow hwnd gW_CHILD
case mchild of
Just hchwnd -> do
clen <- getWindowTextLength (hchwnd)
case clen of
0 -> return 1
_ -> do
str <- newCString (replicate (fromEnum clen) ' ')
getWindowText hwnd str $ clen+1
print =<< peekCString str
free str >> return 0
Nothing -> return 1
main = do
enptr <- wrapEnumWindowsProc findFirstNamedChildWindow
enumWindows enptr 0
return ()
我收到以下错误消息:
C:\Users\me>ghc nc.hs
Linking nc.exe ...
nc.o:fake:(.text+0x958): undefined reference to `GetWindowText@12'
nc.o:fake:(.text+0xe12): undefined reference to `GetWindowTextLength@4'
collect2: ld returned 1 exit status
所有4个功能都在User32.dll中。 GHC版本是7.8.2(32位),OS是Windows 7(64)。
如果我添加此C文件:
#include <windows.h>
int getWindowText (HWND hwnd, char* str, int len) {
return GetWindowText (hwnd, str, len);
}
int getWindowTextLength (HWND hwnd) {
return GetWindowTextLength (hwnd);
}
并更改导入调用
foreign import call "getWindowText"
foreign import call "getWindowTextLength"
一切都按预期工作。 到底是怎么回事?关于隐式演员或类似的事情?我尝试了Foreign.C.String中的宽字符串函数但是没有改变任何东西。 (也就是传递字符串缓冲区以便C写入或者有更好的方法吗?)
答案 0 :(得分:9)
大多数处理字符串的Windows函数有两个版本,一个带有A
后缀的ANSI版本和带有W
后缀的Unicode版本。
例如,GetWindowText
实际上是导出为GetWindowTextA
和GetWindowTextW
两个函数。这些名称显示在bottom of the documentation附近。
对于LPTSTR
版本,LPSTR
参数被解释为A
,对于LPWSTR
版本,W
被解释为GetWindowText
。您可以使用任一功能,但显然您必须使用适当的字符串类型。
C版本有效,因为GetWindowTextA
实际上是一个扩展为GetWindowTextW
或UNICODE
的C宏,具体取决于您是否定义了{{1}}宏。