Is it possible to capture the screen (or a window) using Haskell in a Windows environment? (ie, taking a screenshot every few minutes or so). If so, how would one go about doing this (again, in Haskell, for a Windows environment)?
More info:
I'm a beginner to Haskell. A friend wants to cut development costs by having me whip together some programs for his accounting firm, but he insists that I use Haskell. He wants a tool that will allow him to monitor the desktops of different Windows XP workstations. It would likely have to be a client/server type application. He only needs to monitor desktop activity, hence why he doesn't want any of the expensive management software that is already on the market. I have sifted through lots of documentation, and only got as far as finding wxHaskell, but I couldn't find much on capturing the screen, especially for Windows environments.
The Approach Tikhon mentioned is correct. Just to add some code to the answer he gave above
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.
This was just quickly put together, but it saves a screenshot of to a file named Foo.bmp.
Ps. To whomever wrote the Win32 Library, nicely done :)
You can also do it in a cross-platform way with GTK.
That would not be much different from doing it with C: Taking a screenshot with 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)])
You should be able to do this with the Win32 API. Based on What is the best way to take screenshots of a Window with C++ in Windows?, you need to get the context of the window and then copy the image from it using GetWindowDC
and BitBlt
respectively.
Looking around the Haskell Win32 API documentation, there is a getWindowDC
function in Graphics.Win32.Window
. This returns an IO HDC
. There is a bitblt
function in Graphics.Win32.GDI.Graphics2D
. This function takes an HDC
along with a bunch of INT
s which presumably correspond to the arguments it takes in C++.
Unfortunately, I don't have a Windows machine handy, so I can't write the actual code. You'll have to figure out how to use the Win32 API functions yourself, which might be a bit of a bother.
When you do, it would be great if you factored it into a library and put it up on Hackage--Windows does not usually get much love in Haskell land (as I myself show :P), so I'm sure other Windows programmers would be grateful for an easy way to take screenshots.