Link to home
Start Free TrialLog in
Avatar of T Hoecherl
T HoecherlFlag for United States of America

asked on

Write to a printer using vb.net

I'm trying to write a vb.net program to write a text file to a printer

I found some code on Microsoft .com and I have copied it to Visual Studio.  Here is the code:

Imports System.IO
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim ofd As New OpenFileDialog()
        If ofd.ShowDialog(Me) Then
            Dim pd As New PrintDialog()
            pd.PrinterSettings = New PrinterSettings()
            If (pd.ShowDialog() = Windows.Forms.DialogResult.OK) Then
                RawPrinterHelper.SendFileToPrinter(pd.PrinterSettings.PrinterName, ofd.FileName)
            End If
        End If
    End Sub 'Button1_Click

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim s As String
        Dim pd As New PrintDialog()

        s = "Hello, this is a test"
        pd.PrinterSettings = New PrinterSettings()
        If (pd.ShowDialog() = DialogResult.OK) Then
            rawprinterhelper.sendstringtoprinter(pd.PrinterSettings.PrinterName, s)
        End If
    End Sub 'Button2_Click
End Class
Public Class RawPrinterHelper
    ' Structure and API declarions:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Structure DOCINFOW
        <MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
    End Structure

    <DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As Long) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFOW) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
       SetLastError:=True, CharSet:=CharSet.Unicode, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
    End Function

    ' SendBytesToPrinter()
    ' When the function is given a printer name and an unmanaged array of  
    ' bytes, the function sends those bytes to the print queue.
    ' Returns True on success or False on failure.
    Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
        Dim hPrinter As IntPtr      ' The printer handle.
        Dim dwError As Int32        ' Last error - in case there was trouble.
        Dim di As DOCINFOW          ' Describes your document (name, port, data type).
        Dim dwWritten As Int32      ' The number of bytes written by WritePrinter().
        Dim bSuccess As Boolean     ' Your success code.

        ' Set up the DOCINFO structure.
        With di
            .pDocName = "My Visual Basic .NET RAW Document"
            .pDataType = "RAW"
        End With
        ' Assume failure unless you specifically succeed.
        bSuccess = False
        If OpenPrinter(szPrinterName, hPrinter, 0) Then
            If StartDocPrinter(hPrinter, 1, di) Then
                If StartPagePrinter(hPrinter) Then
                    ' Write your printer-specific bytes to the printer.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
                    EndPagePrinter(hPrinter)
                End If
                EndDocPrinter(hPrinter)
            End If
            ClosePrinter(hPrinter)
        End If
        ' If you did not succeed, GetLastError may give more information
        ' about why not.
        If bSuccess = False Then
            dwError = Marshal.GetLastWin32Error()
        End If
        Return bSuccess
    End Function ' SendBytesToPrinter()

    ' SendFileToPrinter()
    ' When the function is given a file name and a printer name,
    ' the function reads the contents of the file and sends the
    ' contents to the printer.
    ' Presumes that the file contains printer-ready data.
    ' Shows how to use the SendBytesToPrinter function.
    ' Returns True on success or False on failure.
    Public Shared Function SendFileToPrinter(ByVal szPrinterName As String, ByVal szFileName As String) As Boolean
        ' Open the file.
        Dim fs As New FileStream(szFileName, FileMode.Open)
        ' Create a BinaryReader on the file.
        Dim br As New BinaryReader(fs)
        ' Dim an array of bytes large enough to hold the file's contents.
        Dim bytes(fs.Length) As Byte
        Dim bSuccess As Boolean
        ' Your unmanaged pointer.
        Dim pUnmanagedBytes As IntPtr

        ' Read the contents of the file into the array.
        bytes = br.ReadBytes(fs.Length)
        ' Allocate some unmanaged memory for those bytes.
        pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
        ' Copy the managed byte array into the unmanaged array.
        Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
        ' Send the unmanaged bytes to the printer.
        bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, fs.Length)
        ' Free the unmanaged memory that you allocated earlier.
        Marshal.FreeCoTaskMem(pUnmanagedBytes)
        Return bSuccess
    End Function ' SendFileToPrinter()

    ' When the function is given a string and a printer name,
    ' the function sends the string to the printer as raw bytes.
    Public Shared Function SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String)
        Dim pBytes As IntPtr
        Dim dwCount As Int32
        ' How many characters are in the string?
        dwCount = szString.Length()
        ' Assume that the printer is expecting ANSI text, and then convert
        ' the string to ANSI text.
        pBytes = Marshal.StringToCoTaskMemAnsi(szString)
        ' Send the converted ANSI string to the printer.
        SendBytesToPrinter(szPrinterName, pBytes, dwCount)
        Marshal.FreeCoTaskMem(pBytes)
    End Function
End Class

When I try to run it by clicking Button 1, I am able to select the text file but then I get the error message on the attached Word doc.  The place in the code where it errors is this:

"If OpenPrinter(szPrinterName, hPrinter, 0) Then"

I don't know how to fix this.

TextToPrinterErrorMessaage.docx
ASKER CERTIFIED SOLUTION
Avatar of Éric Moreau
Éric Moreau
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of T Hoecherl

ASKER

This is what I now have, after importing System.Diagnostics:

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim MyProcess As New Process
        MyProcess.StartInfo.FileName = "c:\test\6012002c.txt"
        MyProcess.StartInfo.Verb = "Print"
        MyProcess.Start()

    End Sub

But it doesn't work.  The code executes without error, but nothing prints.

How do I specify a destination printer?
Forgive me.  My previous comment was in error.  I had specified a .txt file that was empty.  The print process does, indeed, work with this code.  But it prints to the default printer.  How can I specify a destination printer?

T
The code needs to look something like this (but this doesn't work, so it's not exactly right)

Imports System
Imports System.Net
Imports System.Net.Sockets

Port = 9100 ' Raw Printing is on port 9100
Host = "nfrc.jonespg.net"  ' This should be in our config table.
Header = "<STX>...<ETX>"   ' IPL Header data from config table.

Dim IPs As IPHostEntry = Dns.Resolve(Host)  ' Grab this host's IPs
Dim IP As IPAddress = IPs.AddressList(0)    ' Let's use the first IP listed for this host.
Dim EP As New IPEndPoint(IP, Port)          ' Establish an endpoint.

' Create the TCP socket.
Dim PrintSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

PrintSocket.Connect(EP)   ' Connect the socket.
PrintSocket.Send(Header)  ' Send the header data.

Dim column_1a As String
Dim selectSQL1a As String = "EXECUTE udp_INTERCEPT_FILE '" & strBatch & "'"

Dim com1a As New SqlCommand(selectSQL1a, cn)
com1a.CommandType = CommandType.Text
cn.Open()

Dim myreader1a As SqlDataReader = com1a.ExecuteReader

While myreader1a.Read

  column_1a = myreader1a.GetString(0)

  ' Parse Some fields (optional)
  OrderNumber = myreader1a.GetString(1)
  OrderNumber = myreader1a.GetString(1)
  .
  .
  .

  ' Send this label.
  PrintSocket.Send("<STX><ESC>E5<CAN><ETX>") ' Start a label
  PrintSocket.Send("<STX>Order #" & OrderNUmber & "-" & LineNumber & "<CR><ETX>")
  PrintSocket.Send("<STX>" & Name & "<CR><ETX>")
  .
  .
  .
  PrintSocket.Send("<STX><ETB><ETX>") ' End this label

End While

PrintSocket.Shutdown(SocketShutdown.Both)  ' Release the socket.
PrintSocket.Close()                        ' Close the connection.
why do you use a socket? I have provided you code that print (using the Process component) and another link to change your default printer. Isn't it working?
This is a program to print specifically formatted labels and it requires the use of IPL or the label printers don't work.  The code you gave me works for printing a file to a printer on 8 1/2 by 11 stock, but I need now to format for the labels as I send the data to the printer.  I have been working with the client's IT Director and he knows how to use IPL, but not how to integrate it with VB.net.  Together we came up with the code in my last post, using sockets, and he says that should work, but we don't have the code exactly right.  I need help from someone who knows vb.net and also knows IPL (Intermec Printing Language) to help me get this code properly constructed.
I never used IPL sorry.

You are probably better ask a new question specific question about IPL since your title and first question are about text file (which was already answered correctly!)
Thank you.