2012-10-11 3 views
0

나는이 코드를 사용하여 인터넷을 사용하고 있습니다.작동하도록 OpenPrinter를 얻을 수 없습니다.

RAW 데이터를 가져 와서 레이블을 인쇄하는 Intermec PM4i 레이블 프린터로 txt 파일을 보내려고합니다. 드라이버를로드하고 컴퓨터에 프린터를 설치했습니다. 프린터 및 팩스로 들어가서 프린터를 선택하고 속성으로 들어가서 프린터로 파일을 보내면 레이블이 인쇄됩니다. 그래서 나는 그것이 작동하는 것을 안다. 그러나이 코드를 실행하면 txt 파일을 묻는 대화 상자가 표시됩니다. 파일을 선택하면 프린터를 선택한 다른 대화 상자가 열립니다. 모든 것은 올바르게 작동하는 것 같습니다. 그러나 코드가 SendBytesToPrinter() 함수로 들어가서 OpenPrinter (szPrinterName.Normalize(), hPrinter, IntPtr.Zero)로 도착하면 szPrinterName.Normalize()에 올바른 프린터 이름이 있습니다. hPrinter 및 IntPtr.Zero는 모두 0의 값을 갖습니다. 이 로 직접 이동이 라인에서 경우는 false bSuccess = 다음 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 (의 0x57) "파라미터가 정확하지 않습니다.」인 ERROR_INVALID_PARAMETER 즉, OpenPrinter 호출에서 매개 변수 중 하나가 잘못되었습니다.

OpenPrinter function 용는 Win32 API 참조는 우리에게 어느 하나

pDefault [IN]       PRINTER_DEFAULTS 구조의 포인터. 이 값은 NULL 일 수 있습니다.

당신은 당신의 전화에 InPtr.Zero이 세트를 가지고 있지만, .NET Framework reference는 InPtr.Zero는 "포인터를 표시하거나가 0으로 초기화 된 핸들"특히이 해당 아님을주의하기 위하여 계속한다고 Nothing. 따라서

은을 OpenPrinter에 대한 올바른 호출은 다음과 같습니다

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

관련 문제