Results 1 to 8 of 8

Thread: Print on Network Printer / winspool API

  1. #1

    Thread Starter
    New Member
    Join Date
    Jun 2016
    Posts
    5

    Print on Network Printer / winspool API

    Hello all,
    I have a problem with my printing code. I'm developing an application in Visual Studio 2015 to print labels on Zebra printers (i created the zpl code, everything it's ok - tested and working). I could print this zpl with an ZPL printer connected to network and having assigned an IP. Everything good until i wanted to print on a network printer (\\computer_name\printer_name).
    I'm using some codes based on WINSPOOL. I tried every version from internet using this method and adapting this to VS 2015, but without success. I get error at WritePrinter function. Here it's my code:

    Code:
    Private Declare Function ClosePrinter Lib "winspool.drv" (ByRef hPrinter As IntPtr) As Boolean
        Private Declare Function EndDocPrinter Lib "winspool.drv" (ByRef hPrinter As IntPtr) As Boolean
        Private Declare Function EndPagePrinter Lib "winspool.drv" (ByRef hPrinter As IntPtr) As Boolean
        Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As IntPtr) As Boolean
        Private Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByRef hPrinter As IntPtr, ByRef Level As Integer, ByRef pDocInfo As DOCINFO) As Integer
        Private Declare Function StartPagePrinter Lib "winspool.drv" (ByRef hPrinter As IntPtr) As Boolean
        Private Declare Function WritePrinter Lib "winspool.drv" (ByRef hPrinter As IntPtr, pBuf As String, ByRef cdBuf As Integer, ByRef pcWritten As Integer) As Boolean
        Private Declare Function GetLastError Lib "kernel32" () As Long
    
        Public Sub PrintFileDirectlyToPrinter(PrinterName, FileName)
            Dim lhPrinter As New System.IntPtr
            Dim lReturn As IntPtr
            Dim lpcWritten As New Integer
            Dim lDoc As Integer
            Dim sWrittenData As String
            Dim MyDocInfo As DOCINFO
            Dim oFSO As Object
            Dim oFS As Object
    
            oFSO = CreateObject("Scripting.FileSystemObject")
            oFS = oFSO.OpenTextFile(FileName)
            Do Until oFS.AtEndOfStream
                sWrittenData = oFS.ReadAll()
            Loop
            oFSO = Nothing
            oFS = Nothing
    
            lReturn = OpenPrinter(PrinterName, lhPrinter, 0)
    
            If lReturn = 0 Then
                MsgBox("The Printer Name wasn't recognized.")
                Exit Sub
    
            End If
            MyDocInfo.pDocName = "Downloaded low-level document"
            MyDocInfo.pOutputFile = vbNullString
            MyDocInfo.pDatatype = vbNullString
            lDoc = StartDocPrinter(lhPrinter, 1, MyDocInfo)
    
            Try
                Call StartPagePrinter(lhPrinter)
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
    
            Dim ErrNo As Long
            lReturn = WritePrinter(lhPrinter, sWrittenData, Len(sWrittenData), lpcWritten)
    
            If lReturn = 0 Then
                MsgBox("ERROR WRITE PRINTER")
    
                ErrNo = GetLastError()
                Console.WriteLine(ErrNo)
    
            End If
    
            lReturn = EndPagePrinter(lhPrinter)
            lReturn = EndDocPrinter(lhPrinter)
            lReturn = ClosePrinter(lhPrinter)
        End Sub
    This line it's giving me ZERO value and i can't understand why:
    Code:
     lReturn = WritePrinter(lhPrinter, sWrittenData, Len(sWrittenData), lpcWritten)
    The printer name is: \\computer\ZDesigner GK420t
    The ErrNo has a value of: 8334595290149421056. I don't know what this means
    Any suggestions about this?
    Thank you.

  2. #2
    PowerPoster
    Join Date
    Jul 2002
    Location
    Dublin, Ireland
    Posts
    2,148

    Re: Print on Network Printer / winspool API

    In VB.NET an Integer is 32 bits so you need to declare GetlastError as :-

    VB Code:
    1. Private Declare Function GetLastError Lib "kernel32" () As Int32
    In order to get the correct error number.

    And you also need to call it immediately after the API call that failed - raising a message box actually overwrites it.

  3. #3

    Thread Starter
    New Member
    Join Date
    Jun 2016
    Posts
    5

    Re: Print on Network Printer / winspool API

    Quote Originally Posted by Merrion View Post
    In VB.NET an Integer is 32 bits so you need to declare GetlastError as :-

    VB Code:
    1. Private Declare Function GetLastError Lib "kernel32" () As Int32
    In order to get the correct error number.

    And you also need to call it immediately after the API call that failed - raising a message box actually overwrites it.
    Hello Merrion,
    Thank you for your fast answer. I understand now with this function.
    I edited the code and changed the lines order
    Code:
     If lReturn = 0 Then
                ErrNo = GetLastError()
                Console.WriteLine("ERNO: " & ErrNo)
                MsgBox("ERROR WRITE PRINTER")
            End If
    The error number is 6. I saw that it's Overflow error. Those are some info about the arguments passed to WritePrinter function
    LEN sWrittenData: 823; lpcWritten: 0
    It's still weird for me about this kind of error.

  4. #4

    Thread Starter
    New Member
    Join Date
    Jun 2016
    Posts
    5

    Re: Print on Network Printer / winspool API

    Hello,
    After i started checking all lines, i saw that StartDocPrinter is returning value 0. The error number for this is 124. Could be this a problem with the printer's security for sharing? The error is about: The system call level is not correct.
    Code:
    StartDocPrinter(lhPrinter, 1, MyDocInfo)
    Any idea on how I should write this function in a correct way?
    Thanks.

  5. #5
    PowerPoster
    Join Date
    Jul 2002
    Location
    Dublin, Ireland
    Posts
    2,148

    Re: Print on Network Printer / winspool API

    Your API declaration for StartDocPrinter looks wrong - I would expect hPrinter and Level parameters to be passed "ByVal" - see this support example

  6. #6

    Thread Starter
    New Member
    Join Date
    Jun 2016
    Posts
    5

    Re: Print on Network Printer / winspool API

    Hello Merrion,
    Thank you for your response.
    I changed the parameters to ByVal, but i receive an error with PInvokeStackImbalance:
    Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in '.....PrintTest.vshost.exe'.

    Additional information: A call to PInvoke function 'PrintTest!PrintTest.InfoEticheta::OpenPrinter' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
    Also, the example from the link you provided it's not working. I'm receiving the same error. Maybe it's a problem of Visual Basic 2015?

  7. #7
    PowerPoster
    Join Date
    Jul 2002
    Location
    Dublin, Ireland
    Posts
    2,148

    Re: Print on Network Printer / winspool API

    I'd suggest you check all your api declarations against the documentation in PInvoke...

  8. #8

    Thread Starter
    New Member
    Join Date
    Jun 2016
    Posts
    5

    Re: Print on Network Printer / winspool API

    Hello Merrion,
    I rewrote all of my declarations based on your provided link, and it finally worked. I could understand better the used functions as well.
    The delay between calling the function and printing on paper (on wireless) is somewhere between 1 sec to 1 1/2 sec and on Ethernet cable is max 1 sec.

    Here it's my code. Maybe it will help other people with Visual Basic 2015. Further I will create functions for logging errors. I will let those for the moment as message box.
    This is inside of a module.
    Code:
    Option Explicit On
    Imports System.Runtime.InteropServices
    
    Module PrintFileDirectlyPrinter
        Structure DOCINFO
            Dim pDocName As String
            Dim pOutputFile As String
            Dim pDatatype As String
        End Structure
        Public Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As IntPtr) As Boolean
        Public Declare Function EndDocPrinter Lib "winspool.drv" (ByVal hPrinter As IntPtr) As Boolean
        Public Declare Function EndPagePrinter Lib "winspool.drv" (ByVal hPrinter As IntPtr) As Boolean
        Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As IntPtr) As Boolean
        Public Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As IntPtr, Level As Integer, ByRef pDocInfo As DOCINFO) As Integer
        Public Declare Function StartPagePrinter Lib "winspool.drv" (ByVal hPrinter As IntPtr) As Boolean
        Public Declare Function WritePrinter Lib "winspool.drv" (ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
        Public Declare Function GetLastError Lib "kernel32" () As Int32
    
        Dim lhPrinter As Long
        Dim lReturn, bSuccess As Boolean
        Dim lpcWritten As Int32
        Dim pbytes, LenString, level As Long
        Dim sWrittenData As String
        Dim MyDocInfo As DOCINFO
        Dim oFSO, oFS As Object
    
        Public Sub PreparePrinter(PrinterName)
            level = 1
            lReturn = OpenPrinter(PrinterName, lhPrinter, 0)
    
            If lReturn = 0 Then
                MsgBox("The Printer Name wasn't recognized.")
                Exit Sub
    
            End If
    
            MyDocInfo.pDocName = "Print Label"
            MyDocInfo.pOutputFile = vbNullString
            MyDocInfo.pDatatype = vbNullString '"RAW"
        End Sub
        Public Sub PrintFileDirectlyToPrinter(PrinterName, FileName)
            
            oFSO = CreateObject("Scripting.FileSystemObject")
            oFS = oFSO.OpenTextFile(FileName)
    
            Do Until oFS.AtEndOfStream
                sWrittenData = oFS.ReadAll()
            Loop
            oFSO = Nothing
            oFS = Nothing
    
            LenString = Len(sWrittenData)
    
            ' get the bytes for string
            pbytes = Marshal.StringToCoTaskMemAnsi(sWrittenData)
    
            ' set by default failure printing
            bSuccess = False
    
            If lReturn Then
    
                If StartDocPrinter(lhPrinter, level, MyDocInfo) Then
    
                    If StartPagePrinter(lhPrinter) Then
    
                        ' Write printer-specific bytes
                        bSuccess = WritePrinter(lhPrinter, pbytes, LenString, lpcWritten)
                        EndPagePrinter(lhPrinter)
                    Else
                        MsgBox("error pageprinter")
                    End If
    
                    EndDocPrinter(lhPrinter)
    
                Else
                    MsgBox("error docprinter")
                End If
                ClosePrinter(lhPrinter)
    
            End If
            ' In case of failure show error number
            If bSuccess = False Then
                MsgBox(Marshal.GetLastWin32Error())
            End If
        End Sub
    End Module
    The PreparePrinter(PrinterName) is called in my main form.
    This topic is resolved
    Thank you for your help. Merrion and have a nice day.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width