Solved

Printing a screen shot from VB.net

Posted on 2010-09-22
10
768 Views
Last Modified: 2012-05-10
Hello All
I have been working on some code that will do a screen capture and then save as a file. This is working OK so now i want to either automatically print the file or automatically attach to an email

Code i have so far is

 Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        ' Copy the form's image into a bitmap.Needed for screen print
        Screenshot.CreateBitmap()
    End Sub

    Public Class Screenshot
        Public Declare Function BitBlt Lib "gdi32" Alias "BitBlt" (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 xSrc As Integer, ByVal ySrc As Integer, ByVal dwRop As Integer) As Integer
        Public Declare Function GetWindowDC Lib "user32" Alias "GetWindowDC" (ByVal hwnd As Integer) As Integer
        Public Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hwnd As Integer, ByVal hdc As Integer) As Integer
        Public Const SRCCOPY As Integer = &HCC0020

        Public Shared Sub CreateBitmap()
            Dim gDest As Graphics
            Dim hdcDest As IntPtr
            Dim hdcSrc As Integer
            Dim MyProcess As New Process
            Dim hWnd As Integer '= Control.Handle.ToInt32
            Dim bmp As Bitmap
            hWnd = Process.GetCurrentProcess.MainWindowHandle.ToInt32
            bmp = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
            gDest = Graphics.FromImage(bmp)
            hdcSrc = GetWindowDC(hWnd)
            hdcDest = gDest.GetHdc
            BitBlt(hdcDest.ToInt32, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, hdcSrc, 0, 0, SRCCOPY)
            gDest.ReleaseHdc(hdcDest)
            ReleaseDC(hWnd, hdcSrc)
            bmp.Save("C:\BITMAP.png")
           
        End Sub

    End Class

Question is now how best to print the file automatically with no user interference and how best to attach to an email

the file format doesnt have to be PNG if any one has a better suggestion

Many thanks in advance
0
Comment
Question by:bostonste
  • 6
  • 3
10 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Your other questions list VB.Net 2008...if this is the case then you can simplify with:

    Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
        Using G As Graphics = Graphics.FromImage(bmp)
            G.CopyFromScreen(0, 0, 0, 0, bmp.Size)
        End Using
        bmp.Save("C:\Screenshot.png", System.Drawing.Imaging.ImageFormat.Png)
    End Sub

*Note that you were not actually saving a PNG in the original code as you have to explicitly set the second parameter.  What you were doing was saving a Bitmap with a .png extension.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
You can print the image using the PrintDocument() class:
http://msdn.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx
0
 
LVL 12

Expert Comment

by:Anuradha Goli
Comment Utility
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;


public partial class Form1 : System.Windows.Forms.Form
{
    private System.ComponentModel.Container components;
    private System.Windows.Forms.Button printButton;
    private Font printFont;
    private StreamReader streamToPrint;

    public Form1()
    {
        // The Windows Forms Designer requires the following call.
        InitializeComponent();
    }

    // The Click event is raised when the user clicks the Print button.
    private void printButton_Click(object sender, EventArgs e)
    {
        try
        {
            streamToPrint = new StreamReader
               ("C:\\My Documents\\MyFile.txt");
            try
            {
                printFont = new Font("Arial", 10);
                PrintDocument pd = new PrintDocument();
                pd.PrintPage += new PrintPageEventHandler
                   (this.pd_PrintPage);
                pd.Print();
            }
            finally
            {
                streamToPrint.Close();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    // The PrintPage event is raised for each page to be printed.
    private void pd_PrintPage(object sender, PrintPageEventArgs ev)
    {
        float linesPerPage = 0;
        float yPos = 0;
        int count = 0;
        float leftMargin = ev.MarginBounds.Left;
        float topMargin = ev.MarginBounds.Top;
        string line = null;

        // Calculate the number of lines per page.
        linesPerPage = ev.MarginBounds.Height /
           printFont.GetHeight(ev.Graphics);

        // Print each line of the file.
        while (count < linesPerPage &&
           ((line = streamToPrint.ReadLine()) != null))
        {
            yPos = topMargin + (count *
               printFont.GetHeight(ev.Graphics));
            ev.Graphics.DrawString(line, printFont, Brushes.Black,
               leftMargin, yPos, new StringFormat());
            count++;
        }

        // If more lines exist, print another page.
        if (line != null)
            ev.HasMorePages = true;
        else
            ev.HasMorePages = false;
    }


    // The Windows Forms Designer requires the following procedure.
    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.printButton = new System.Windows.Forms.Button();

        this.ClientSize = new System.Drawing.Size(504, 381);
        this.Text = "Print Example";

        printButton.ImageAlign =
           System.Drawing.ContentAlignment.MiddleLeft;
        printButton.Location = new System.Drawing.Point(32, 110);
        printButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
        printButton.TabIndex = 0;
        printButton.Text = "Print the file.";
        printButton.Size = new System.Drawing.Size(136, 40);
        printButton.Click += new System.EventHandler(printButton_Click);

        this.Controls.Add(printButton);
    }

}
0
 

Author Comment

by:bostonste
Comment Utility
Hello All

After reading all your posts i have made adjustments to my code as folows
 Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        ' Copy the form's image into a bitmap.Needed for screen print
        Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
        Using G As Graphics = Graphics.FromImage(bmp)
            G.CopyFromScreen(0, 0, 0, 0, bmp.Size)
        End Using
        bmp.Save("C:\Screenshot.bmp", System.Drawing.Imaging.ImageFormat.Bmp)
        streamToPrint = New StreamReader("C:\Screenshot.bmp")
        Try
            printFont = New Font("Arial", 10)
            Dim pd As New PrintDocument()
            AddHandler pd.PrintPage, AddressOf Me.pd_PrintPage
            pd.Print()
        Finally
            streamToPrint.Close()
        End Try
    End Sub
    Private Sub pd_PrintPage(ByVal sender As Object, ByVal ev As PrintPageEventArgs)
        Dim linesPerPage As Single = 0
        Dim yPos As Single = 0
        Dim count As Integer = 0
        Dim leftMargin As Single = ev.MarginBounds.Left
        Dim topMargin As Single = ev.MarginBounds.Top
        Dim line As String = Nothing
        ' Calculate the number of lines per page.
        linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics)
        ' Print each line of the file.
        While count < linesPerPage
            line = streamToPrint.ReadLine()
            If line Is Nothing Then
                Exit While
            End If
            yPos = topMargin + count * printFont.GetHeight(ev.Graphics)
            ev.Graphics.DrawString(line, printFont, Brushes.Black, leftMargin, yPos, New StringFormat())
            count += 1
        End While
        ' If more lines exist, print another page.
        If (line IsNot Nothing) Then
            ev.HasMorePages = True
        Else
            ev.HasMorePages = False
        End If
    End Sub

This saves a screen shot , starts the print process but it then gives me numerous pages of rubbish instead of a picture.

Where have i gone wrong

Cheers
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Just move the "bmp" declaration up to CLASS level:

    Private bmp As Bitmap

    Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click
        ' Copy the form's image into a bitmap.Needed for screen print
        bmp = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)

Then use DrawImage() in the PrintPage() event:

    ev.Graphics.DrawImage(bmp, x, y)
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:bostonste
Comment Utility
Almost there and many thanks so far

I now have this code for the printpage event

       Dim linesPerPage As Single = 0
        Dim yPos As Single = 0
        Dim xPos As Single = 0
        Dim count As Integer = 0
        Dim leftMargin As Single = ev.MarginBounds.Left
        Dim topMargin As Single = ev.MarginBounds.Top
        Dim line As String = Nothing
        ' Calculate the number of lines per page.
        linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics)
        ' Print each line of the file.
        While count < linesPerPage
            line = streamToPrint.ReadLine()
            If line Is Nothing Then
                Exit While
            End If
            yPos = topMargin + count * printFont.GetHeight(ev.Graphics)
            ev.Graphics.DrawImage(bmp, leftMargin, topMargin)
            count += 1
        End While
        ev.HasMorePages = False
    End Sub

wich does print but , but only about a quarter of the screen shot on a page, is it possible to make it all fit on a single page
(A4)

Thanks
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
Comment Utility
Sure...look at all the overloads for DrawImage():
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.drawimage.aspx

You can specify a "destination size" which will resize the image into that area...LOTS of different ways to do it!

This overload simply takes a Rectangle specify the destination location/size:
http://msdn.microsoft.com/en-us/library/yws82c40.aspx

    "Draws the specified Image at the specified location and with the specified size."

So you'd define a Rectangle like this:

    Dim rc As New Rectangle(leftMargin, topMargin, desiredWidthHere, desiredHeightHere)

Then pass that to DrawImage():

    ev.Graphics.DrawImage(bmp, rc)

*If your only printing ONE page then get rid of all the paging code!
0
 

Author Closing Comment

by:bostonste
Comment Utility
My code is now down to this
    Dim leftMargin As Single = 5 'ev.MarginBounds.Left
        Dim topMargin As Single = 5 'ev.MarginBounds.Top
        Dim rc As New Rectangle(leftMargin, topMargin, 850, 1100)
        ev.Graphics.DrawImage(bmp, rc)
    End Sub

many thanks

On a side note is it possible to amend my code to only capture the active form on the screen rather than the whols screen ??
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Yes...but you have to use some APIs to accomplish this...

First, get the "active" window with GetForegroundWindow(), then pass that to GetWindowRect() to determine its location/size.  Armed with that info you can now modify your existing code to only read that portion of the screen:

    Public Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
    End Structure

    Private Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" _
        (ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Integer

    Private Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr

To get the active window and its location/size:

    Dim ActiveWindow As IntPtr = GetForegroundWindow()
    Dim ActiveRECT As RECT
    GetWindowRect(ActiveWindow, ActiveRect)
    Dim sz As New Size(ActiveRECT.Right - ActiveRECT.Left + 1, ActiveRECT.Bottom - ActiveRECT.Top + 1)
 
Now use "ActiveRECT" and "sz" in the CopyFromScreen() call:

    G.CopyFromScreen(ActiveRECT.Left, ActiveRECT.Top, 0, 0, sz)
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
*Also use "sz" to determine the size of your dynamic Bitmap:

    Dim bmp As New Bitmap(sz.Width, sz.Height)
    Using G As Graphics = Graphics.FromImage(bmp)
        G.CopyFromScreen(ActiveRECT.Left, ActiveRECT.Top, 0, 0, sz)
    End Using
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
This video teaches viewers about errors in exception handling.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now