• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 881
  • Last Modified:

Printing a screen shot from VB.net

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
bostonste
Asked:
bostonste
  • 6
  • 3
1 Solution
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
You can print the image using the PrintDocument() class:
http://msdn.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx
0
 
Anuradha GoliCommented:
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
Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

 
bostonsteAuthor Commented:
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
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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
 
bostonsteAuthor Commented:
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
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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
 
bostonsteAuthor Commented:
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
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
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
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
*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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

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