2012-10-11 116 views
0

我正在使用此代碼,我下了網。無法打開OpenPrinter工作

我想發送一個txt文件到一個Intermec PM4i標籤打印機,該打印機需要RAW數據並打印出標籤。我已經加載驅動程序並在機器上安裝了打印機。我可以進入打印機和傳真機選擇打印機並進入屬性並將文件發送到打印機,並打印出標籤。所以我知道它的工作原理。但是當我運行這個代碼時,它首先出現一個對話框,詢問txt文件。一旦選擇了文件,另一個對話框將打開您選擇打印機的位置。所有似乎正常工作。但是,當代碼進入SendBytesToPrinter()函數並獲取到OpenPrinter(szPrinterName.Normalize(),hPrinter,IntPtr.Zero)時,szPrinterName.Normalize()具有正確的打印機名稱。 hPrinter和IntPtr.Zero都具有零值。 從這個線就直接進入 如果bSuccess = false,那麼 dwError = Marshal.GetLastWin32Error() 結束如果 而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 

回答

1

我對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); 
    } 
0

Win32 Error code 87(0×57)是ERROR_INVALID_PARAMETER, 「參數不正確」。換句話說,您打電話給OpenPrinter的其中一個參數是錯誤的。

OpenPrinter function的Win32 API的參考告訴我們其中之一:

pDefault [IN]      指向一個PRINTER_DEFAULTS結構。該值可以是NULL。

你有這樣的設置爲InPtr.Zero在您的電話,但.NET Framework reference指出InPtr.Zero「代表一個指針或手柄已被初始化爲零」,並接着特別提醒說,這是相當於到Nothing

因此,爲了OpenPrinter正確的調用是:

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

相關問題