2012-08-15 8 views
12

Ist es möglich, den Bildschirm (oder ein Fenster) mit Haskell in einer Windows-Umgebung zu erfassen? (dh alle paar Minuten einen Screenshot machen). Wenn ja, wie würde man das machen (wieder in Haskell für eine Windows-Umgebung)?Bildschirmaufnahme in Haskell?

Weitere Informationen: Ich bin ein Anfänger zu Haskell. Ein Freund möchte die Entwicklungskosten senken, indem er einige Programme für seine Wirtschaftsprüfungsgesellschaft zusammenpeitscht, aber er besteht darauf, dass ich Haskell benutze. Er möchte ein Tool, mit dem er die Desktops verschiedener Windows XP-Workstations überwachen kann. Es müsste wahrscheinlich eine Client/Server-Anwendung sein. Er muss nur die Desktop-Aktivitäten überwachen, und deshalb möchte er keine der teuren Management-Software, die bereits auf dem Markt ist. Ich habe viele Dokumentationen durchforstet und bin nur soweit gekommen, wxHaskell zu finden, aber ich konnte nicht viel auf dem Bildschirm finden, besonders für Windows-Umgebungen.

+0

Haben Sie darüber nachgedacht, nur ein externes Programm von Haskell aufzurufen, das einen Screenshot erstellt? – Probie

+0

@Probie In der Tat habe ich überlegt, den Client und den Server in Haskell zu erstellen und die Screenshots in verschiedenen Intervallen zu senden. ABER, das scheint so kontraintuitiv zu sein. Warum sollte man überhaupt Haskell benutzen, wenn nur ein kleiner Teil der Software Haskell ist? Leider ist es etwas, das die Haskell Gemeinschaft ansprechen sollte. Wenn wir möchten, dass Haskell bekannter wird, müssen wir diese Art von Problemen definitiv lösen. –

Antwort

17

Der Ansatz Tikhon erwähnt ist korrekt. Nur um einige Code auf die Antwort hinzufügen er über

gab
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. 

Dies wurde nur schnell zusammen, aber es spart einen Screenshot in eine Datei namens diese als foo.bmp. Ps. Für wen auch immer schrieb die Win32-Bibliothek, nett gemacht :)

+0

Sieht gut aus! Dies wird mir definitiv bei meinen Abenteuern mit Haskell helfen. Vielen Dank! –

11

Sie sollten dies mit der Win32-API tun können. Basierend auf What is the best way to take screenshots of a Window with C++ in Windows?, müssen Sie den Kontext des Fensters abrufen und dann das Bild davon mit GetWindowDC bzw. BitBlt kopieren.

Wenn Sie sich die Haskell Win32-API-Dokumentation ansehen, gibt es in Graphics.Win32.Window eine getWindowDC-Funktion. Dies gibt eine IO HDC zurück. Es gibt eine bitblt Funktion in Graphics.Win32.GDI.Graphics2D. Diese Funktion nimmt eine HDC zusammen mit einer Reihe von INT s, die vermutlich die Argumente in C++ entsprechen.

Leider habe ich keine Windows-Maschine zur Hand, daher kann ich den eigentlichen Code nicht schreiben. Sie müssen herausfinden, wie Sie die Win32-API-Funktionen selbst verwenden, was ein wenig lästig sein könnte.

Wenn Sie das tun, wäre es toll, wenn Sie es in eine Bibliothek faktorisiert und es auf Hackage setzen - Windows bekommt normalerweise nicht viel Liebe in Haskell Land (wie ich selbst zeige: P), also bin ich sicher, dass andere Windows-Programmierer dankbar wären für eine einfache Möglichkeit, Screenshots zu machen.

12

Sie können es auch in einer plattformübergreifenden Weise mit GTK.

Das wäre nicht viel anders als mit 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)]) 
+0

Dieser Ansatz sieht sehr sauber und unkompliziert aus. Ich werde es mir merken. Obwohl es sehr ähnlich wäre, würde ich gerne einige Beispiele in Haskell sehen, da ich noch ein Anfänger bin. –

+0

@ M.Ferguson, hier gehts.Es stellte sich heraus, dass es etwas anders war: Ich fand das Äquivalent zu 'gdk_get_default_root_window' nicht, daher wurde ein zusätzlicher Aufruf von' screenGetDefault' benötigt. – Rotsor

+0

@Rotsor 'gdk_get_default_root_window' ist mit' Graphics.UI.Gtk.Gdk.DrawWindow.drawWindowGetDefaultRootWindow' umwickelt, nicht die einfachste Sache zu finden, obwohl –