Link to home
Start Free TrialLog in
Avatar of Marshalltown
Marshalltown

asked on

Problem with API Printer functions

I am currently working on a project to convert a VB6 program over to Visual Studio 2008. The current piece of the program that I am working on uses the API OpenPrinter, ClosePrinter etc functions to print labels. The issue that I am having is that whenever I migrated the code over everything seems to work except for whenever I pull the printer handler. For some reason whenever I try to print, the new Visual Studio 2008 program pulls back the printer handler as a 0. if anybody has any ideas on what might cause this i would appreciate it. I have attached my code below. Thanks in advance for any information.
' Here are the declared functions
 ' 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 IntPtr) As Boolean
        End Function
 
        ' Private Declare Function OpenPrinter Lib "winspool.drv" Alias _
        '   "OpenPrinterA" (ByVal pPrinterName As String, ByVal phPrinter As IntPtr, _
        '   ByVal pDefault As Int32) As Long
 
 
        <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
 
        ' Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal _
        'hPrinter As IntPtr) As Long
 
 
        <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
 
        ' Private Declare Function StartDocPrinter Lib "winspool.drv" Alias _
        '   "StartDocPrinterA" (ByVal hPrinter As IntPtr, ByVal Level As Int32, _
        '   ByVal pDocInfo As DOCINFO) As Long
 
 
        <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
 
        ' Private Declare Function EndDocPrinter Lib "winspool.drv" (ByVal _
        '   hPrinter As IntPtr) As Long
 
 
        <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
 
        ' Private Declare Function StartPagePrinter Lib "winspool.drv" (ByVal _
        '   hPrinter As IntPtr) As Long
 
        <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
 
        ' Private Declare Function EndPagePrinter Lib "winspool.drv" (ByVal _
        '   hPrinter As IntPtr) As Long
 
 
        <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 String, ByVal dwCount As IntPtr, ByRef dwWritten As Int32) As Boolean
        End Function
 
        ' Private Declare Function WritePrinter Lib "winspool.drv" (ByVal _
        '   hPrinter As IntPtr, ByVal pBuf As String, ByVal cdBuf As IntPtr, _
        '   ByVal pcWritten As IntPtr) As Long
 
 
'And here is where the functions are called, lhprinter is coming back as a 0 instead of the 
' printer handler
 
Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As String, 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 = "Label"
                .pDataType = vbNullString
                .pOutputFile = vbNullString
            End With
            dwWritten = dwCount
            ' Assume failure unless you specifically succeed.
            bSuccess = False
            If OpenPrinter(szPrinterName, hPrinter, IntPtr.Zero) 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()

Open in new window

Avatar of oobayly
oobayly
Flag of United Kingdom of Great Britain and Northern Ireland image

Try passing the IntPtr parameter in OpenPrinter ByVal instead of ByRef.
In this statement
OpenPrinter(szPrinterName, hPrinter, IntPtr.Zero)

What is the parameter pd for? You are supplying it IntPtr.Zero
From MSDN, pd is a pointer to a PrinterDefaults structure and is allowed to be null.

Sorry, my suggestion about byVal is just plain wrong, it should be ByRef in VB. The reason I mentioned it was that I had some issues with IntPtrs being passed by ref in a C# project a while ago. I can't for the life of me remember the details though.

I've just tried the OpenPrinter import on my machine and it's worked for all three printers installed. Sounds like a stupid question, but have you tried copying the printer name from the Printer Properties dialog in Control Panel? Any additional whitespace will cause it to fail.

Also, what error do you get after OpenPrinter fails:
'' Create this exception after the call fails.
'' It will contain the error description & native error code.
Dim ex As New System.ComponentModel.Win32Exception()

Open in new window

Avatar of Marshalltown
Marshalltown

ASKER

Actually the weird part about this is that I don't get any error at all. Two things happen if I choose the Entry Point that was in the original VB6 code (OpenPrinterA) then the printer handler just comes back as  a 0, and it runs through the rest of my code but nothing happens. But if I change the entry point to the one you see in the code above (OpenPrinterW) then it will pull back the printer handler. Today I stepped through the code with the printer queue open so I could watch what was happening, and as I stepped through the code I could see the file go out to the printer queue as raw data just as it should, and then it would change to a status of printing, and then whenever EndDocPrinter would run (which is usually when the label would come out of the printer) nothing happens and the file is removed from the printer queue.
oobayly,  I actually already have a GetLastWin32Error after I call the api functions later in the project, but it is not coming back with any error.
ASKER CERTIFIED SOLUTION
Avatar of Marshalltown
Marshalltown

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