0

我正在使用我从网上下载的这段代码。

我正在尝试将 txt 文件发送到 Intermec PM4i 标签打印机,该打印机获取 RAW 数据并打印出标签。我已经加载了驱动程序并在机器上设置了打印机。我可以进入打印机和传真选择打印机并进入属性并将文件发送到打印机,它将打印出标签。所以我知道它有效。但是当我运行这段代码时,它会从一个对话框开始,要求输入 txt 文件。选择文件后,将打开另一个对话框,您可以在其中选择打印机。所有这些似乎都正常工作。但是当代码进入 SendBytesToPrinter() 函数并到达 OpenPrinter(szPrinterName.Normalize(), hPrinter, IntPtr.Zero) 时,szPrinterName.Normalize() 具有正确的打印机名称。hPrinter 和 IntPtr.Zero 的值都为零。从这一行开始,它直接转到 If bSuccess = False Then dwError = Marshal。GetLastWin32Error() End If And Marshal.GetLastWin32Error() 的值为 87。就是这样,没有打印任何内容。请让我知道发生了什么事?谢谢

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices
Imports System.IO

Public Class Form1

    ' Structure and API declarions:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Public Class DOCINFOA
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pDocName As String
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pOutputFile As String
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pDataType As String
    End Class
    <DllImport("winspool.Drv", EntryPoint:="OpenPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function OpenPrinter(<MarshalAs(UnmanagedType.LPStr)> ByVal szPrinter As String, ByVal hPrinter As IntPtr, ByVal pd As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="StartDocPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, <[In](), MarshalAs(UnmanagedType.LPStruct)> ByVal di As DOCINFOA) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="WritePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByVal 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, false on failure.
    Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
        Dim dwError As Int32 = 0, dwWritten As Int32 = 0
        Dim hPrinter As New IntPtr(0)
        Dim di As New DOCINFOA()
        Dim bSuccess As Boolean = False
        ' Assume failure unless you specifically succeed.
        di.pDocName = "My C#.NET RAW Document"
        di.pDataType = "RAW"

        Try
            ' Open the printer.
            If OpenPrinter(szPrinterName.Normalize(), hPrinter, IntPtr.Zero) Then
                ' Start a document.
                If StartDocPrinter(hPrinter, 1, di) Then
                    ' Start a page.
                    If StartPagePrinter(hPrinter) Then
                        ' Write your bytes.
                        bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
                        EndPagePrinter(hPrinter)
                    End If
                    EndDocPrinter(hPrinter)
                End If
                ClosePrinter(hPrinter)
            End If
        Catch ex As Exception
            MsgBox("error")
        End Try

        ' 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

    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 big enough to hold the file's contents.
        Dim bytes As [Byte]() = New [Byte](fs.Length - 1) {}
        Dim bSuccess As Boolean = False
        ' Your unmanaged pointer.
        Dim pUnmanagedBytes As New IntPtr(0)
        Dim nLength As Integer

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

    Public Shared Function SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String) As Boolean
        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)
        Return True
    End Function





    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If True Then
            ' Allow the user to select a file.
            Dim ofd As New OpenFileDialog()
            If DialogResult.OK = ofd.ShowDialog(Me) Then
                ' Allow the user to select a printer.
                Dim pd As New PrintDialog()
                pd.PrinterSettings = New PrinterSettings()
                If DialogResult.OK = pd.ShowDialog(Me) Then
                    ' Print the file to the printer.

                    SendFileToPrinter(pd.PrinterSettings.PrinterName, ofd.FileName)
                End If
            End If
        End If

    End Sub
End Class
4

2 回答 2

2

我有一些 OpenPrinter 的 C# 代码,应该很容易翻译。

[DllImport("winspool.drv", EntryPoint = "OpenPrinter", SetLastError = true)]
internal static extern bool OpenPrinter(string pPrinterName, ref IntPtr phPrinter, PRINTER_DEFAULTS pDefault);

[DllImport("winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true)]
internal static extern int ClosePrinter(IntPtr hPrinter);

[StructLayout(LayoutKind.Sequential)]
public class PRINTER_DEFAULTS
{
    public string pDatatype;
    public IntPtr pDevMode;
    public int DesiredAccess;
}

public struct OpenPrinterAccessCodes
{
    public const int DELETE = 0x10000; // DELETE - Allowed to delete printers
    public const int READ_CONTROL = 0x20000; // READ_CONTROL - Allowed to read printer information
    public const int WRITE_DAC = 0x40000; // WRITE_DAC - Allowed to write device access control info
    public const int WRITE_OWNER = 0x80000; // WRITE_OWNER - Allowed to change the object owner
    public const int SERVER_ACCESS_ADMINISTER = 0x1;
    public const int SERVER_ACCESS_ENUMERATE = 0x2;
    public const int PRINTER_ACCESS_ADMINISTER = 0x4;
    public const int PRINTER_ACCESS_USE = 0x8;
    public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
    public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
    public const int SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE);

    public const int MAX_PORTNAME_LEN = 64;
    public const int MAX_NETWORKNAME_LEN = 49;
    public const int MAX_SNMP_COMMUNITY_STR_LEN = 33;
    public const int MAX_QUEUENAME_LEN = 33;
    public const int MAX_IPADDR_STR_LEN = 16;

    public const int ERROR_INSUFFICIENT_BUFFER = 122;
    public const int ERROR_INVALID_FLAGS = 1004;
}
    public IntPtr OpenPrinterHandle(string printerName)
    {
        var def = new PRINTER_DEFAULTS { pDatatype = null, pDevMode = IntPtr.Zero, DesiredAccess = OpenPrinterAccessCodes.PRINTER_ALL_ACCESS };
        var hPrinter = IntPtr.Zero;
        if (!OpenPrinter(printerName, ref hPrinter, def))
        {
            var lastWin32Error = new Win32Exception(Marshal.GetLastWin32Error());
            Logger.Log("Failed open Printer: " + lastWin32Error.Message);
            throw lastWin32Error;
        }
        return hPrinter;
    }

    public void ClosePrinterHandle(IntPtr hPrinter)
    {
        ClosePrinter(hPrinter);
    }
于 2012-12-19T00:17:55.747 回答
0

Win32 错误代码87 (0x57) 是 ERROR_INVALID_PARAMETER,“参数不正确。” 换句话说,您调用 OpenPrinter 的参数之一是错误的。

OpenPrinter 函数的 Win32 API 参考告诉我们是哪一个:

pDefault [in] 指向 PRINTER_DEFAULTS 结构的指针。该值可以为 NULL。

您在调用中已将此设置为InPtr.Zero,但.NET Framework 参考声明 InPtr.Zero “表示已初始化为零的指针或句柄”,并继续特别警告它等同于Nothing.

因此,对 OpenPrinter 的正确调用是:

OpenPrinter(szPrinterName.Normalize(), hPrinter, Nothing)

于 2013-08-20T18:09:04.167 回答