13

是否可以在 Windows 环境中使用 Haskell 捕获屏幕(或窗口)?(即每隔几分钟左右截屏一次)。如果是这样,人们将如何去做(同样,在 Haskell 中,对于 Windows 环境)?

更多信息:我是 Haskell 的初学者。一个朋友想通过让我为他的会计师事务所编写一些程序来降低开发成本,但他坚持让我使用 Haskell。他想要一个工具,可以让他监控不同 Windows XP 工作站的桌面。它可能必须是客户端/服务器类型的应用程序。他只需要监控桌面活动,因此他不想要任何已经在市场上的昂贵管理软件。我筛选了很多文档,只找到了 wxHaskell,但在捕获屏幕方面我找不到太多,尤其是对于 Windows 环境。

4

3 回答 3

19

Tikhon 提到的方法是正确的。只是在他上面给出的答案中添加一些代码

import Graphics.Win32.Window
import Graphics.Win32.GDI.Bitmap
import Graphics.Win32.GDI.HDC
import Graphics.Win32.GDI.Graphics2D

main = do desktop   <- getDesktopWindow -- Grab the Hwnd of the desktop, GetDC 0, GetDC NULL etc all work too
          hdc       <- getWindowDC (Just desktop) -- Get the dc handle of the desktop
          (x,y,r,b) <- getWindowRect desktop -- Find the size of the desktop so we can know which size the destination bitmap should be
                                             -- (left, top, right, bottom)
          newDC     <- createCompatibleDC (Just hdc) -- Create a new DC to hold the copied image. It should be compatible with the source DC
          let width  = r - x -- Calculate the width
          let height = b - y -- Calculate the Height
          newBmp    <- createCompatibleBitmap hdc width height -- Create a new Bitmap which is compatible with the newly created DC
          selBmp    <- selectBitmap newDC newBmp -- Select the Bitmap into the DC, drawing on the DC now draws on the bitmap as well
          bitBlt newDC 0 0 width height hdc 0 0 sRCCOPY -- use SRCCOPY to copy the desktop DC into the newDC
          createBMPFile "Foo.bmp" newBmp newDC  -- Write out the new Bitmap file to Foo.bmp
          putStrLn "Bitmap image copied" -- Some debug message
          deleteBitmap selBmp -- Cleanup the selected bitmap
          deleteBitmap newBmp -- Cleanup the new bitmap
          deleteDC newDC      -- Cleanup the DC we created.

这只是快速组合在一起,但它将屏幕截图保存到名为 Foo.bmp 的文件中。附言。对于编写 Win32 库的人来说,做得很好:)

于 2012-08-15T09:29:05.800 回答
14

您也可以使用GTK以跨平台的方式进行。

这与使用 C 进行操作没有太大区别:使用 C/GTK 截屏

{-# LANGUAGE OverloadedStrings #-}

import Graphics.UI.Gtk
import System.Environment
import Data.Text as T

main :: IO ()
main = do
    [fileName] <- getArgs
    _ <- initGUI
    Just screen <- screenGetDefault
    window <- screenGetRootWindow screen
    size <- drawableGetSize window
    origin <- drawWindowGetOrigin window
    Just pxbuf <-
        pixbufGetFromDrawable
            window
            ((uncurry . uncurry Rectangle) origin size)
    pixbufSave pxbuf fileName "png" ([] :: [(T.Text, T.Text)])
于 2012-08-15T15:46:49.140 回答
12

您应该能够使用 Win32 API 执行此操作。基于在 Windows 中使用 C++ 截取窗口的最佳方法是什么?GetWindowDC,您需要获取窗口的上下文,然后分别使用和从中复制图像BitBlt

查看 Haskell Win32 API 文档,getWindowDCGraphics.Win32.Window. 这将返回一个IO HDC. 中有一个bitblt函数Graphics.Win32.GDI.Graphics2D。这个函数需要一个sHDC和一堆INTs,这些 s 大概对应于它在C++中的参数。

不幸的是,我手边没有 Windows 机器,所以我无法编写实际代码。您必须自己弄清楚如何使用 Win32 API 函数,这可能有点麻烦。

当你这样做的时候,如果你把它放入一个库并将它放在 Hackage 上,那就太好了——Windows 在 Haskell 领域通常不会得到太多的喜爱(正如我自己展示的那样:P),所以我相信其他 Windows 程序员将不胜感激一种简单的方法来截取屏幕截图。

于 2012-08-15T04:23:21.677 回答