Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4872
  • Last Modified:

Background app that takes screenshots

Hi,

     1) I would like to have a background application that runs without any visible windows.

      2) I would like this app to take a screenshot once every 5 - 60 minutes, depending on user settings, and save it to a directory.  A counter in a text file will determine unique names for each bitmap.  

       I know I've read something about background process apps before, but I don't know how to create one.  I'm also guessing sending windows a command to take a screenshot (same as hitting Print Screen button and saving the result) is pretty simple, but have no idea how to do it.

Thanks!

JP
0
gleznov
Asked:
gleznov
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Here is an app that runs from the system tray (Be sure to set an icon for the Icon property of the NotifyIcon1 control).  The files are saved in BMP format using the following naming convention:

    Capture_05Nov2004_170441.bmp

If you double click the tray icon, a form will appear that will allow you to change the screen capture interval in minutes.  Minimizing the form will send it back to the tray.

Hope you find it helpful,

Idle_Mind

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents Label1 As System.Windows.Forms.Label
    Friend WithEvents NotifyIcon1 As System.Windows.Forms.NotifyIcon
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents NumericUpDown1 As System.Windows.Forms.NumericUpDown
    Friend WithEvents Label2 As System.Windows.Forms.Label
    Friend WithEvents Label3 As System.Windows.Forms.Label
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form1))
        Me.Label1 = New System.Windows.Forms.Label
        Me.NotifyIcon1 = New System.Windows.Forms.NotifyIcon(Me.components)
        Me.Button1 = New System.Windows.Forms.Button
        Me.NumericUpDown1 = New System.Windows.Forms.NumericUpDown
        Me.Label2 = New System.Windows.Forms.Label
        Me.Label3 = New System.Windows.Forms.Label
        CType(Me.NumericUpDown1, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        '
        'Label1
        '
        Me.Label1.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.Label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.Label1.Location = New System.Drawing.Point(104, 8)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(184, 24)
        Me.Label1.TabIndex = 2
        Me.Label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
        '
        'NotifyIcon1
        '
        Me.NotifyIcon1.Icon = CType(resources.GetObject("NotifyIcon1.Icon"), System.Drawing.Icon)
        Me.NotifyIcon1.Text = "Screen Capture Demo"
        '
        'Button1
        '
        Me.Button1.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.Button1.Location = New System.Drawing.Point(8, 72)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(280, 24)
        Me.Button1.TabIndex = 3
        Me.Button1.Text = "Take ScreenShot Now"
        '
        'NumericUpDown1
        '
        Me.NumericUpDown1.Location = New System.Drawing.Point(56, 8)
        Me.NumericUpDown1.Maximum = New Decimal(New Integer() {60, 0, 0, 0})
        Me.NumericUpDown1.Minimum = New Decimal(New Integer() {5, 0, 0, 0})
        Me.NumericUpDown1.Name = "NumericUpDown1"
        Me.NumericUpDown1.Size = New System.Drawing.Size(40, 20)
        Me.NumericUpDown1.TabIndex = 4
        Me.NumericUpDown1.Value = New Decimal(New Integer() {5, 0, 0, 0})
        '
        'Label2
        '
        Me.Label2.Location = New System.Drawing.Point(8, 8)
        Me.Label2.Name = "Label2"
        Me.Label2.Size = New System.Drawing.Size(48, 24)
        Me.Label2.TabIndex = 5
        Me.Label2.Text = "Interval:"
        Me.Label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
        '
        'Label3
        '
        Me.Label3.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.Label3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
        Me.Label3.Location = New System.Drawing.Point(8, 40)
        Me.Label3.Name = "Label3"
        Me.Label3.Size = New System.Drawing.Size(280, 24)
        Me.Label3.TabIndex = 6
        Me.Label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(296, 102)
        Me.Controls.Add(Me.Label3)
        Me.Controls.Add(Me.Label2)
        Me.Controls.Add(Me.NumericUpDown1)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.Label1)
        Me.Name = "Form1"
        Me.Text = "Screen Capture Demo"
        Me.WindowState = System.Windows.Forms.FormWindowState.Minimized
        CType(Me.NumericUpDown1, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Const SRCCOPY = &HCC0020

    Private Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, ByVal lpInitData As String) As Integer
    Private Declare Function CreateCompatibleDC Lib "GDI32" (ByVal hDC As Integer) As Integer
    Private Declare Function CreateCompatibleBitmap Lib "GDI32" (ByVal hDC As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer) As Integer
    Private Declare Function SelectObject Lib "GDI32" (ByVal hDC As Integer, ByVal hObject As Integer) As Integer
    Private Declare Function BitBlt Lib "GDI32" (ByVal hDestDC As Integer, ByVal X As Integer, ByVal Y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hSrcDC As Integer, ByVal SrcX As Integer, ByVal SrcY As Integer, ByVal Rop As Integer) As Integer
    Private Declare Function DeleteObject Lib "GDI32" (ByVal hObj As Integer) As Integer
    Private Declare Function DeleteDC Lib "GDI32" (ByVal hDC As Integer) As Integer
    Private Declare Function RegisterHotKey Lib "user32" (ByVal hWnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Boolean
    Private Declare Function UnregisterHotKey Lib "user32" (ByVal hWnd As IntPtr, ByVal id As Integer) As Boolean

    Private loading As Boolean = True
    Private WithEvents t As System.Timers.Timer

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        t = New System.Timers.Timer
        t.Interval = 100
        t.Start()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        takeScreenShot()
    End Sub

    Private Sub takeScreenShot()
        Dim SR As Rectangle = Screen.PrimaryScreen().GetBounds(New Point(0, 0))
        Dim b As Bitmap = GetScreen(SR.Left, SR.Top, SR.Width, SR.Height)
        Dim imgName As String = "c:\Capture_" & Now.ToString("ddMMMyyyy_HHmmss") & ".bmp"
        b.Save(imgName)
        Label3.Text = imgName
    End Sub

    Private Function GetScreen(ByVal X As Integer, ByVal Y As Integer, ByVal Width As Integer, ByVal Height As Integer) As Bitmap
        Dim hDeskDC As Integer
        Dim hTempDC As Integer
        Dim hBitmap As Integer
        Dim hTempBmp As Integer
        Dim desktopArea As Bitmap

        hDeskDC = CreateDC("DISPLAY", "", "", "")
        If hDeskDC Then
            hTempDC = CreateCompatibleDC(hDeskDC)
            If hTempDC Then
                hBitmap = CreateCompatibleBitmap(hDeskDC, Width, Height)
                If hBitmap Then
                    hTempBmp = SelectObject(hTempDC, hBitmap)
                    BitBlt(hTempDC, 0, 0, Width, Height, hDeskDC, X, Y, SRCCOPY)
                    desktopArea = Bitmap.FromHbitmap(New IntPtr(hBitmap))
                    DeleteObject(SelectObject(hTempDC, hTempBmp))
                End If
                DeleteDC(hTempDC)
            End If
            DeleteDC(hDeskDC)
        End If
        Return desktopArea
    End Function

    Private Sub Form1_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.SizeChanged
        If Me.WindowState = FormWindowState.Minimized Then
            Me.Hide()
            NotifyIcon1.Visible = True
        End If
    End Sub

    Private Sub NotifyIcon1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles NotifyIcon1.DoubleClick
        NotifyIcon1.Visible = False
        Me.Show()
        Me.WindowState = FormWindowState.Normal
    End Sub

    Private Sub t_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles t.Elapsed
        If loading Then
            Debug.WriteLine("loading")
            t.Stop()
            loading = False
            Me.Hide()
            NotifyIcon1.Visible = True
            t.Interval = NumericUpDown1.Value * 60000
            Label1.Text = "Next Capture @ " & DateTime.Now.AddMinutes(NumericUpDown1.Value).ToLongTimeString
            t.Start()
        Else
            Debug.WriteLine(Now.ToShortDateString & "_" & Now.ToShortTimeString)
            takeScreenShot()
            t.Interval = NumericUpDown1.Value * 60000
            Label1.Text = "Next Capture @ " & DateTime.Now.AddMinutes(NumericUpDown1.Value).ToLongTimeString
        End If
    End Sub

    Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown1.ValueChanged
        If Not (t Is Nothing) Then
            t.Interval = NumericUpDown1.Value * 60000
            Label1.Text = "Next Capture @ " & DateTime.Now.AddMinutes(NumericUpDown1.Value).ToLongTimeString
        End If
    End Sub
End Class
0
 
armoghanCommented:
Wow Idle_Mind did it all
just to add one more thing..

If you dont want to show it at all, not even in the taskbar, make it a Windows Service
0
 
gleznovAuthor Commented:
Thank you both!
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
JazzleCommented:
Any chance this could be compiled and posted somewhere online?
Would be very much appreciated.
J
0
 
OLisyCommented:
It works fine, but when I run it as Windows Service, I got interop GDI+ error when calling the save function. Any idea? Thanks :Ol

Error: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
   at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
   at System.Drawing.Image.Save(String filename, ImageFormat format)
   at System.Drawing.Image.Save(String filename)
   at ScreenShots.Service.takeScreenShot()

0
 
OLisyCommented:
The System Service started saving ScreenShots, when I used strong name, registered it in GAC and set file system writing rights to the System Service user.

But all ScreenShots are black. It didn't change when I tried to save it in JPG format. Still black. Any idea? Thanks :Ol
0
 
armoghanCommented:
if you are taking pictures of a running Movie in media player,
It cannot be screen shoted. As it is written directly into memory.

Even print screen cannot take it
0
 
OLisyCommented:
All right, but still I don't understand why the above described screenshoting solution works as WinForm Application, but not as System Service. Even when the System Service run under user, which is equal to logged on user.
0
 
BarnaculesCommented:
Print Screen in Vista+ will show screen shot output of Media Player provided it is not DRM content. Also the reason you get a black screen when taking a screen shot from a service is because the service runs in Session 0 which is the secure desktop so you are not going to get a picture of what is going on with the active logged on session. Your best bet for what you are doing is to create a standalone application and set the showintasktray attribute of your form to false and hige the window (.hide()). Good luck!
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now