Hi, just to chuck my views on this topic
We also have this problem, im sure the code works to the winspool.drv
but a more "noddy" approach we came up with, which also seems to work, we
scan and print to zebras on networks
Set up the printer on a server so that can print to it the same as below
execute a cmdprompt bur hidden, so the user has no idea that this is
happening then
1) delete a net use command to lpt6
2) create a net use mapping lpt6 to the printer (we've set that as an
configurable option in the application)
3) save the zpl codes to a text file
4) use a type command to print to LPT6
do you have any sample code i could look at?
'Option Explicit On
Option Strict Off
Imports System.IO
Imports System.Runtime.InteropServices
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
'UP: Geändert wegen unbalanced stack fehlermeldung
<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 Integer) 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
Declare Auto Function GetPrinter Lib "winspool.drv" (ByVal
hPrinter As _
IntPtr, ByVal Level As Integer, ByRef pPrinter As Byte, ByVal
cbBuf _
As Integer, ByRef pcbNeeded As Integer) As Boolean
' 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 = Nothing ' 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
Dim ByteBuf As Integer
Dim BytesNeeded As Int32
Dim PrinterInfo2 As New PRINTER_INFO_2
Dim PrinterInfo() As Byte
Dim result As Boolean
'Determine the buffer size that is required to obtain the
printer information.
result = GetPrinter(hPrinter, 2, 0&, 0, BytesNeeded)
'Display the error message that you receive when you call
the GetPrinter function,
'and then close the printer handle.
dwError = Marshal.GetLastWin32Error()
If dwError <> ERROR_INSUFFICIENT_BUFFER And _
dwError <> 0 Then
Try
ClosePrinter(hPrinter)
Catch ex As Exception
End Try
Throw New MESPopupException("DCS-1031",
MESPopup.MeldungsTypen.Fehler, szPrinterName, dwError.ToString)
End If
ReDim PrinterInfo(BytesNeeded)
ByteBuf = BytesNeeded
'Call the GetPrinter function to obtain the status.
result = GetPrinter(hPrinter, 2, PrinterInfo(0), ByteBuf,
BytesNeeded)
'Check for any errors.
If Not result Then
'Get the error.
dwError = Marshal.GetLastWin32Error()
Try
ClosePrinter(hPrinter)
Catch ex As Exception
End Try
Throw New MESPopupException("DCS-1031",
MESPopup.MeldungsTypen.Fehler, szPrinterName, dwError.ToString)
End If
PrinterInfo2 = CType(DatatoDeserial(PrinterInfo,
GetType(PRINTER_INFO_2), 1), PRINTER_INFO_2)
If PrinterInfo2.Status <> 0 Then
Throw New MESPopupException("DCS-1032",
MESPopup.MeldungsTypen.Fehler, szPrinterName,
GetPrinterStatusText(PrinterInfo2.Status))
Exit Function
End If
' Im Falle, dass der Drucker ohne Spooler konfiguriert
wurde,
' erfolgt bei Druckerproblemen (z.B. Netzwerk) keine
Rückmeldung vom Betriebssystem
' und die Methode EndDocPrinter bleibt hängen. Dazu wird
diese Methode mittels eines
' zusätzlichen Threads mit Timeout von 20s gestartet
' Um Übergabeparameter an den Thread übergeben zu können,
wird ein Objekt der Klasse
' "PrinterThread" angelegt und die Property pHandle
gesetzt
Dim myPrinterThreadObj As New PrinterThread
myPrinterThreadObj.m_pHandle = hPrinter
myPrinterThreadObj.m_DocInfo = di
Dim myThread As System.Threading.Thread
myThread = New System.Threading.Thread(AddressOf
myPrinterThreadObj.StartDocPrinter)
myThread.Start()
Dim retBool As Boolean = myThread.Join(10000)
If Not retBool Then
myThread.Abort()
Throw New MESPopupException("DCS-1030",
MESPopup.MeldungsTypen.Fehler, "Timeout")
End If
bSuccess = myPrinterThreadObj.retVal
If bSuccess Then bSuccess = StartPagePrinter(hPrinter)
' Write your printer-specific bytes to the printer.
If bSuccess Then bSuccess = WritePrinter(hPrinter, pBytes,
dwCount, dwWritten)
If bSuccess Then bSuccess = EndPagePrinter(hPrinter)
'If StartDocPrinter(hPrinter, 1, di) Then
' If StartPagePrinter(hPrinter) Then
' ' Write your printer-specific bytes to the
printer.
' bSuccess = WritePrinter(hPrinter, pBytes,
dwCount, dwWritten)
' bSuccess = EndPagePrinter(hPrinter)
' End If
If bSuccess Then
myThread = New System.Threading.Thread(AddressOf
myPrinterThreadObj.EndDocPrinter)
myThread.Start()
retBool = myThread.Join(10000)
If Not retBool Then
myThread.Abort()
Throw New MESPopupException("DCS-1030",
MESPopup.MeldungsTypen.Fehler, "Timeout")
End If
End If
'bSuccess = 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()
Const ERROR_INVALID_PRINTER_NAME As Int32 = 1801
Const ERROR_INVALID_PRINTER_COMMAND As Int32 = 1803
Const ERROR_PRINTER_OUT_OF_PAPER As Int32 = 28
Const ERROR_INVALID_PRINTER_STATE As Int32 = 1906
Const ERROR_PRINTER_NOT_FOUND As Int32 = 3012
Select Case dwError
Case ERROR_INVALID_PRINTER_NAME
'DCS-1025 = Drucker {0} ist unter Windows nicht
bekannt!
Throw New MESPopupException("DCS-1025",
MESPopup.MeldungsTypen.Fehler, szPrinterName)
Case ERROR_INVALID_PRINTER_COMMAND
'DCS-1026 = Druckkommando {0} ist ungültig!
Throw New MESPopupException("DCS-1026",
MESPopup.MeldungsTypen.Fehler, szPrinterName)
Case ERROR_PRINTER_OUT_OF_PAPER
'DCS-1027 = Drucker {0} hat kein Papier!
Throw New MESPopupException("DCS-1027",
MESPopup.MeldungsTypen.Fehler, szPrinterName)
Case ERROR_INVALID_PRINTER_STATE
'DCS-1028 = Drucker {0} ist nicht bereit!
Throw New MESPopupException("DCS-1028",
MESPopup.MeldungsTypen.Fehler, szPrinterName)
Case ERROR_PRINTER_NOT_FOUND
'DCS-1029 = Drucker {0} nicht gefunden!
Throw New MESPopupException("DCS-1029",
MESPopup.MeldungsTypen.Fehler, szPrinterName)
Case Else
'DCS-1030 = Unbekannter Fehler beim Ausdruck des
Etiketts! Fehlercode: {1}
Throw New MESPopupException("DCS-1030",
MESPopup.MeldungsTypen.Fehler, dwError.ToString)
End Select
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(CInt(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(CInt(fs.Length))
' Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(CInt(fs.Length))
' Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, CInt(fs.Length))
' Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes,
CInt(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 Sub SendStringToPrinter(ByVal szPrinterName As
String, ByVal szString As String)
Dim pBytes As IntPtr
Dim dwCount As Int32
szString = System.Text.Encoding.Default.GetString( _
System.Text.Encoding.GetEncoding(850).GetBytes(szString))
' 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 Sub
End Class
Module CheckPrinterStatus
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Structure PRINTER_INFO_2
Public pServerName As Integer
Public pPrinterName As Integer
Public pShareName As Integer
Public pPortName As Integer
Public pDriverName As Integer
Public pComment As Integer
Public pLocation As Integer
Public pDevMode As Integer
Public pSepFile As Integer
Public pPrintProcessor As Integer
Public pDatatype As Integer
Public pParameters As Integer
Public pSecurityDescriptor As Integer
Public Attributes As Integer
Public Priority As Integer
Public DefaultPriority As Integer
Public StartTime As Integer
Public UntilTime As Integer
Public Status As Integer
Public cJobs As Integer
Public AveragePPM As Integer
End Structure
Public Function DatatoDeserial(ByVal datas() As Byte, ByVal
type_to_change As Type, _
ByVal NumJub As Long) As Object
'Returns the size of the JOB_INFO_2 structure
'HACK: Changed Long to integer
Dim Data_to_Size As Integer = Marshal.SizeOf(type_to_change)
If Data_to_Size > datas.Length Then
Return Nothing
End If
Dim buffer As IntPtr = Marshal.AllocHGlobal(Data_to_Size)
Dim startindex As Long
Dim i As Integer
For i = 0 To NumJub - 1
If i = 0 Then
startindex = 0
Else
startindex = startindex + Data_to_Size
End If
Next
'Copy data from the datas array to the unmanaged memory
pointer.
Marshal.Copy(datas, startindex, buffer, Data_to_Size)
'Marshal data from the buffer pointer to a managed object.
Dim result_obj As Object = Marshal.PtrToStructure(buffer,
type_to_change)
'Free the memory that is allocated from the unmanaged memory.
Marshal.FreeHGlobal(buffer)
Return result_obj
End Function
'Define the printer status constants.
Public Const ERROR_INSUFFICIENT_BUFFER As Integer = 122
Public Const PRINTER_STATUS_BUSY As Integer = &H200
Public Const PRINTER_STATUS_DOOR_OPEN As Integer = &H400000
Public Const PRINTER_STATUS_ERROR As Integer = &H2
Public Const PRINTER_STATUS_INITIALIZING As Integer = &H8000
Public Const PRINTER_STATUS_IO_ACTIVE As Integer = &H100
Public Const PRINTER_STATUS_MANUAL_FEED As Integer = &H20
Public Const PRINTER_STATUS_NO_TONER As Integer = &H40000
Public Const PRINTER_STATUS_NOT_AVAILABLE As Integer = &H1000
Public Const PRINTER_STATUS_OFFLINE As Integer = &H80
Public Const PRINTER_STATUS_OUT_OF_MEMORY As Integer = &H200000
Public Const PRINTER_STATUS_OUTPUT_BIN_FULL As Integer = &H800
Public Const PRINTER_STATUS_PAGE_PUNT As Integer = &H80000
Public Const PRINTER_STATUS_PAPER_JAM As Integer = &H8
Public Const PRINTER_STATUS_PAPER_OUT As Integer = &H10
Public Const PRINTER_STATUS_PAPER_PROBLEM As Integer = &H40
Public Const PRINTER_STATUS_PAUSED As Integer = &H1
Public Const PRINTER_STATUS_PENDING_DELETION As Integer = &H4
Public Const PRINTER_STATUS_PRINTING As Integer = &H400
Public Const PRINTER_STATUS_PROCESSING As Integer = &H4000
Public Const PRINTER_STATUS_TONER_LOW As Integer = &H20000
Public Const PRINTER_STATUS_USER_INTERVENTION As Integer =
&H100000
Public Const PRINTER_STATUS_WAITING As Integer = &H2000
Public Const PRINTER_STATUS_WARMING_UP As Integer = &H10000
Public Function GetPrinterStatusText(ByVal PI2Status As Long) As
String
Dim tempStr As String
If PI2Status = 0 Then ' Return the "Ready" status.
GetPrinterStatusText = "Ready"
Else
tempStr = ""
'Determine the printer state.
If (PI2Status And PRINTER_STATUS_BUSY) Then
tempStr = tempStr & "Busy"
End If
If (PI2Status And PRINTER_STATUS_DOOR_OPEN) Then
tempStr = tempStr & "Printer Door Open"
End If
If (PI2Status And PRINTER_STATUS_ERROR) Then
tempStr = tempStr & "Printer Error"
End If
If (PI2Status And PRINTER_STATUS_INITIALIZING) Then
tempStr = tempStr & "Initializing"
End If
If (PI2Status And PRINTER_STATUS_IO_ACTIVE) Then
tempStr = tempStr & "I/O Active"
End If
If (PI2Status And PRINTER_STATUS_MANUAL_FEED) Then
tempStr = tempStr & "Manual Feed"
End If
If (PI2Status And PRINTER_STATUS_NO_TONER) Then
tempStr = tempStr & "No Toner"
End If
If (PI2Status And PRINTER_STATUS_NOT_AVAILABLE) Then
tempStr = tempStr & "Not Available"
End If
If (PI2Status And PRINTER_STATUS_OFFLINE) Then
tempStr = tempStr & "Off Line"
End If
If (PI2Status And PRINTER_STATUS_OUT_OF_MEMORY) Then
tempStr = tempStr & "Out of Memory"
End If
If (PI2Status And PRINTER_STATUS_OUTPUT_BIN_FULL) Then
tempStr = tempStr & "Output Bin Full"
End If
If (PI2Status And PRINTER_STATUS_PAGE_PUNT) Then
tempStr = tempStr & "Page Punt"
End If
If (PI2Status And PRINTER_STATUS_PAPER_JAM) Then
tempStr = tempStr & "Paper Jam"
End If
If (PI2Status And PRINTER_STATUS_PAPER_OUT) Then
tempStr = tempStr & "Paper Out"
End If
If (PI2Status And PRINTER_STATUS_OUTPUT_BIN_FULL) Then
tempStr = tempStr & "Output Bin Full"
End If
If (PI2Status And PRINTER_STATUS_PAPER_PROBLEM) Then
tempStr = tempStr & "Page Problem"
End If
If (PI2Status And PRINTER_STATUS_PAUSED) Then
tempStr = tempStr & "Paused"
End If
If (PI2Status And PRINTER_STATUS_PENDING_DELETION) Then
tempStr = tempStr & "Pending Deletion"
End If
If (PI2Status And PRINTER_STATUS_PRINTING) Then
tempStr = tempStr & "Printing"
End If
If (PI2Status And PRINTER_STATUS_PROCESSING) Then
tempStr = tempStr & "Processing"
End If
If (PI2Status And PRINTER_STATUS_TONER_LOW) Then
tempStr = tempStr & "Toner Low"
End If
If (PI2Status And PRINTER_STATUS_USER_INTERVENTION) Then
tempStr = tempStr & "User Intervention"
End If
If (PI2Status And PRINTER_STATUS_WAITING) Then
tempStr = tempStr & "Waiting"
End If
If (PI2Status And PRINTER_STATUS_WARMING_UP) Then
tempStr = tempStr & "Warming Up"
End If
If Len(tempStr) = 0 Then
tempStr = "Unknown Status of " & PI2Status
End If
'Return the status.
GetPrinterStatusText = tempStr
End If
End Function
End Module
Public Class PrinterThread
Public m_pHandle As System.IntPtr
Public m_DocInfo As RawPrinterHelper.DOCINFOW ' Describes
your document (name, port, data type).
Public retVal As Boolean
Public Sub EndDocPrinter()
retVal = RawPrinterHelper.EndDocPrinter(m_pHandle)
End Sub
Public Sub StartDocPrinter()
retVal = RawPrinterHelper.StartDocPrinter(m_pHandle, 1,
m_DocInfo)
End Sub
End Class