Hi,

I'm printing a VB.NET form using BitBlt API my code as follows:

' create a printing component
    Private WithEvents pd As Printing.PrintDocument

    ' storage for form image
    Dim formImage As Bitmap

    ' create API prototype
    Private Declare Function BitBlt Lib "gdi32.dll" Alias _
       "BitBlt" (ByVal hdcDest As IntPtr, _
       ByVal nXDest As Integer, ByVal nYDest As _
       Integer, ByVal nWidth As Integer, _
       ByVal nHeight As Integer, ByVal _
       hdcSrc As IntPtr, ByVal nXSrc As Integer, _
       ByVal nYSrc As Integer, _
       ByVal dwRop As System.Int32) As Long



    Private Sub GetFormImageToPrint()
        Dim g As Graphics = Me.CreateGraphics()
        Dim formSize As Size = Me.Size

        formImage = New Bitmap(formSize.Width, formSize.Height, g)

        Dim mg As Graphics = Graphics.FromImage(formImage)
        Dim dc1 As IntPtr = g.GetHdc
        Dim dc2 As IntPtr = mg.GetHdc


        ' added code to compute and capture the form 
        ' title bar and borders 
        Dim widthDiff As Integer = _
           (Me.Width - Me.ClientRectangle.Width)
        Dim heightDiff As Integer = _
           (Me.Height - Me.ClientRectangle.Height)
        Dim borderSize As Integer = widthDiff \ 2
        Dim heightTitleBar As Integer = heightDiff - borderSize
        BitBlt(dc2, 0, 0, _
           Me.ClientRectangle.Width + widthDiff, _
           Me.ClientRectangle.Height + heightDiff, dc1, _
           0 - borderSize, 0 - heightTitleBar, 13369376)

        g.ReleaseHdc(dc1)
        mg.ReleaseHdc(dc2)
    End Sub

    ' Callback from PrintDocument component to do the actual printing
    Private Sub pd_PrintPage(ByVal sender As Object, _
       ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
       Handles pd.PrintPage

        Dim sz As SizeF = formImage.GetBounds(GraphicsUnit.Pixel).Size
        'scale image if it unscaled doesn't fit marginbounds
        If sz.Height > e.MarginBounds.Size.Height Or sz.Width > e.MarginBounds.Size.Width Then
            Dim scaleheight As Double = sz.Height / e.MarginBounds.Size.Height
            Dim scalewidth As Double = sz.Width / e.MarginBounds.Size.Width
            Dim scale As Double = Math.Max(scalewidth, scaleheight)
            scalewidth = sz.Width / scale
            scaleheight = sz.Height / scale
            sz = New SizeF(CSng(scalewidth), CSng(scaleheight))
            Dim scalebounds As New RectangleF(e.MarginBounds.Location, sz)
            'draw scaled image
            e.Graphics.DrawImage(formImage, scalebounds)
        Else
            'draw unscaled image
            e.Graphics.DrawImageUnscaled(formImage, e.MarginBounds)
        End If


        'e.Graphics.DrawImage(formImage, 0, 0)

    End Sub

    Private Sub mnuPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuPrint.Click

        PrintScr()
    End Sub

    Private Sub PrintScr()

        Try

            GetFormImageToPrint()
            ' create an instance of the PrintDocument component
            pd = New Printing.PrintDocument

            If PrintDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
                pd.PrinterSettings = PrintDialog1.PrinterSettings
                pd.Print()
            End If

        Catch ex As Exception
            ErrorMsg(" Error number:" & Err.Number & Chr(13) & "Error Description:" & Err.Description, ParentForm.Text)

        End Try



        Exit Sub

    End Sub

the problem I have is the File menu (mnuFile which contains mnuPrint and about 5 other mnu's) remains on screen thus being also printed. Any ideas how I can close the menu before GetFormImageToPrint is executed.

Cheers
Darren

Hi,

I think you can't, because your making a printscreen and that will be printing.

What you need is the create a bitmap that only prints the client area.
here's an example:

Private Declare Auto Function BitBlt Lib "gdi32.dll" (ByVal _
    hdcDest As IntPtr, ByVal nXDest As Integer, ByVal _
    nYDest As Integer, ByVal nWidth As Integer, ByVal _
    nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc _
    As Integer, ByVal nYSrc As Integer, ByVal dwRop As _
    System.Int32) As Boolean
Private Const SRCCOPY As Integer = &HCC0020

' Variables used to print.
Private m_PrintBitmap As Bitmap
Private WithEvents m_PrintDocument As PrintDocument

' Print the picture.
Private Sub btnPrint_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnPrint.Click
    ' Copy the form's image into a bitmap.
    m_PrintBitmap = GetFormImage()

    ' Make a PrintDocument and print.
    m_PrintDocument = New PrintDocument
    m_PrintDocument.Print()
End Sub

Private Function GetFormImage() As Bitmap
    ' Get this form's Graphics object.
    Dim me_gr As Graphics = Me.CreateGraphics

    ' Make a Bitmap to hold the image.
    Dim bm As New Bitmap(Me.ClientSize.Width, _
        Me.ClientSize.Height, me_gr)
    Dim bm_gr As Graphics = me_gr.FromImage(bm)
    Dim bm_hdc As IntPtr = bm_gr.GetHdc

    ' Get the form's hDC. We must do this after 
    ' creating the new Bitmap, which uses me_gr.
    Dim me_hdc As IntPtr = me_gr.GetHdc

    ' BitBlt the form's image onto the Bitmap.
    BitBlt(bm_hdc, 0, 0, Me.ClientSize.Width, _
        Me.ClientSize.Height, _
        me_hdc, 0, 0, SRCCOPY)
    me_gr.ReleaseHdc(me_hdc)
    bm_gr.ReleaseHdc(bm_hdc)

    ' Return the result.
    Return bm
End Function

' Print the form image.
Private Sub m_PrintDocument_PrintPage(ByVal sender As _
    Object, ByVal e As _
    System.Drawing.Printing.PrintPageEventArgs) Handles _
    m_PrintDocument.PrintPage
    ' Draw the image centered.
    Dim x As Integer = e.MarginBounds.X + _
        (e.MarginBounds.Width - m_PrintBitmap.Width) \ 2
    Dim y As Integer = e.MarginBounds.Y + _
        (e.MarginBounds.Height - m_PrintBitmap.Height) \ 2
    e.Graphics.DrawImage(m_PrintBitmap, x, y)

    ' There's only one page.
    e.HasMorePages = False
End Sub

Thanks for input guys....

adatapost, I hid the MenuBar but it still printed the unwanted menu.

Luc001, I replaced my code with yours but it still printed the unwanted menu.

VB6 worked a treat using the PrintWindowVB api. But using in .Net started causing problems ie the Unwanted menu hence why I started looking at BitBlt api.

Cheers
Darren

Comments
Thanks.

Correct me if I am wrong. Are you turn off Control menu? I have turn off visible property (say MenuStrip1 control) and got output without menu. I have also used VB.NET PrintForm utility control and got same result (In this case you can turn off controls menu).

I have used the code which was in previous posts and also from the - http://www.knowdotnet.com/articles/printform.html

MenuStrip1.Visible = False
GetFormImage()
pd.Print()

Code using PrintForm control.

MenuStrip1.Visible = False
PrintForm1.PrintAction = Printing.PrintAction.PrintToPreview
PrintForm1.Print(Me, PowerPacks.Printing.PrintForm.PrintOption.ClientAreaOnly)

Hi,

I found a way how to hide the Menu.
I did it in VB 2003 and added a MainMenu to it.
Now to hide the mainmenu I've used MainMenu1.Dispose like this.

Private Function GetFormImage() As Bitmap
        ' Get this form's Graphics object.
        Dim me_gr As Graphics = Me.CreateGraphics

        ' Make a Bitmap to hold the image.
        Dim bm As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height, me_gr)
        Dim bm_gr As Graphics = me_gr.FromImage(bm)
        Dim bm_hdc As IntPtr = bm_gr.GetHdc

        ' Get the form's hDC. We must do this after 
        ' creating the new Bitmap, which uses me_gr.
        Dim me_hdc As IntPtr = me_gr.GetHdc

        ' BitBlt the form's image onto the Bitmap.
        BitBlt(bm_hdc, 0, 0, Me.ClientSize.Width, Me.ClientSize.Height, _
            me_hdc, 0, 0, SRCCOPY)
        me_gr.ReleaseHdc(me_hdc)
        bm_gr.ReleaseHdc(bm_hdc)

        ' Return the result.
        Return bm
        MainMenu1.Dispose()  ' Add this part of code into the function
    End Function

Edited 6 Years Ago by Luc001: n/a

Hi,,

adatapost, the PrintForm works great to a certain extent and I dont have to hide the the Menu. However is there a way I can scale the image to fit on one page and automatically adjust the orientation?

I was doing this:

Private Sub Pd_BeginPrint(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles pd.BeginPrint
        pd.DefaultPageSettings.Landscape = False
        Dim sz As SizeF = formImage.GetBounds(GraphicsUnit.Pixel).Size
        Dim pw As Integer = pd.DefaultPageSettings.Bounds.Width
        pw -= pd.DefaultPageSettings.Margins.Left
        pw -= pd.DefaultPageSettings.Margins.Right
        'landscape if image unscaled is wider than marginbounds width
        If sz.Width > pw Then pd.DefaultPageSettings.Landscape = True

    End Sub

and this for scaling:

Private Sub pd_PrintPage(ByVal sender As Object, _
       ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
       Handles pd.PrintPage
 
        Dim sz As SizeF = formImage.GetBounds(GraphicsUnit.Pixel).Size
        'scale image if it unscaled doesn't fit marginbounds
        If sz.Height > e.MarginBounds.Size.Height Or sz.Width > e.MarginBounds.Size.Width Then
            Dim scaleheight As Double = sz.Height / e.MarginBounds.Size.Height
            Dim scalewidth As Double = sz.Width / e.MarginBounds.Size.Width
            Dim scale As Double = Math.Max(scalewidth, scaleheight)
            scalewidth = sz.Width / scale
            scaleheight = sz.Height / scale
            sz = New SizeF(CSng(scalewidth), CSng(scaleheight))
            Dim scalebounds As New RectangleF(e.MarginBounds.Location, sz)
            'draw scaled image
            e.Graphics.DrawImage(formImage, scalebounds)
        Else
            'draw unscaled image
            e.Graphics.DrawImageUnscaled(formImage, e.MarginBounds)
        End If
 
 
        'e.Graphics.DrawImage(formImage, 0, 0)
 
    End Sub

Luc001, Thanks but the Dispose will destroy the Menu

Thanks for your help on this:)
Darren

In your Print event, simply add the form update method

Private Sub PrintToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PrintToolStripMenuItem.Click
        Me.Update()
        Me.PrintForm1.Print()
    End Sub

It will force the redraw of the form prior to executing the print command. The problem is that the PrintForm control takes over immediately and the form has not yet had time to redraw.

Just Separate your print section that means what you want see in print section by a groupbox

create a group box and cover the area you want to print and take a btn and label it as Print and its name to btnPrint double click button write this code

PrintPreviewDialog1.Document = PrintDocument1
        PrintPreviewDialog1.PrintPreviewControl.Zoom = 1
        PrintPreviewDialog1.ShowDialog()

take a "print preview dailog" and "print document" from toolbox in print preview dailog select the document to printdocument1 and double click on printdocument write this code

Dim GroupBox1Image As New Bitmap(Me.GroupBox1.Width, Me.GroupBox1.Height)
        GroupBox1.DrawToBitmap(GroupBox1Image, New Rectangle(0, 0, Me.GroupBox1.Width, Me.GroupBox1.Height))
        e.Graphics.DrawImage(GroupBox1Image, 0, 0)
    replace your group box name thats all it have done
This article has been dead for over six months. Start a new discussion instead.