【问题标题】:Haskell undefined reference when calling some win32 api functions调用某些win32 api函数时的Haskell未定义引用
【发布时间】:2014-05-05 09:19:03
【问题描述】:

我正在尝试编写一些未包含在 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 位),操作系统为 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 写入的预期方法还是有更好的方法?)

【问题讨论】:

    标签: c winapi haskell ffi


    【解决方案1】:

    大多数处理字符串的 Windows 函数都有两个版本,一个带有 A 后缀的 ANSI 版本和一个带有 W 后缀的 Unicode 版本。

    例如,GetWindowText 实际上导出为两个函数,GetWindowTextAGetWindowTextW。这些名称出现在bottom of the documentation 附近。

    LPTSTR 参数对于 A 版本解释为 LPSTR,对于 W 版本解释为 LPWSTR。您可以使用任一函数,但显然您必须使用适当的字符串类型来配合它。

    C 版本可以工作,因为 GetWindowText 实际上是一个 C 宏,它可以扩展为 GetWindowTextAGetWindowTextW,具体取决于您是否定义了 UNICODE 宏。

    【讨论】:

    • 谢谢,foreign import stdcall "windows.h GetWindowTextLengthA" 工作正常。
    猜你喜欢
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    相关资源
    最近更新 更多