Как открыть кассовый ящик, который связан с чековым принтером с помощью C#

Кто-нибудь знает, как открыть кассовый ящик из приложения C#, когда кассовый ящик подключен к чековому принтеру? У меня есть два отчета в моей заявке о том, что кассовый ящик первого чека откроется в печати, а во втором - кассовый ящик не должен быть открыт. Я должен попытаться использовать POS для dll.Net в моем приложении, но dll не обнаружил принтеры чеков или кассовый чек.

1 ответ

Решение

У меня есть для вас решение, которое я использую для своего приложения на C#. Я нашел исходный код в VB.NET и просто создал библиотеку классов, на которую я ссылаюсь, потому что я не мог быть обеспокоен созданием версии C#. Вы можете, конечно, конвертировать его, если хотите, но, по крайней мере, это поможет вам начать.

Я опубликую ВСЕ классы, которые я использую в моей библиотеке классов Invoice.Framework.Printer.

Imports System.IO
Imports System.Drawing.Printing
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

<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 Int32) 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

' 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          ' 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
        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()

' 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(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(fs.Length)
    ' Allocate some unmanaged memory for those bytes.
    pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
    ' Copy the managed byte array into the unmanaged array.
    Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
    ' Send the unmanaged bytes to the printer.
    bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, 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 Function SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String)
    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)
End Function

End Class

Есть класс, который содержит коды, специфичные для того, что вы ищете, в частности, код, который вы отправляете на принтер, чтобы открыть ящик.

Public Module Globals
    Public fullPaperCutCode = Chr(27) & Chr(109)
    Public drawerCode = Chr(27) & Chr(112) & Chr(48) & Chr(55) & Chr(121)
    Public partialPaperCutCode = Chr(27) & Chr(105)
End Module

Затем у меня был небольшой класс, который я написал, чтобы просто открыть кассовый ящик для конкретного принтера чеков.

Public Class CashDrawer
    Public Shared Sub OpenCashDrawer(printerName As String)
        RawPrinterHelper.SendStringToPrinter(printerName, drawerCode)
    End Sub
End Class

Параметр printerName в приведенном выше коде - это имя принтера в том виде, в каком оно написано в апплете панели управления ваших устройств и принтеров. Я использовал этот код с рядом принтеров чеков, совместимых с Epson и Epson, и все они работали на меня, чтобы открыть кассовый ящик, подключенный через телефонную розетку к принтеру чеков. В моем случае все мои чековые принтеры были подключены через USB, если ваши принтеры подключены через RJ45 к сети, затем установите их как принтеры на основе IP и попробуйте приведенный выше код, не знаю, сработает ли он, поскольку я никогда не пробовал подобным образом,

Извините, код VB.NET... хотя я уверен, что вы можете найти способ поместить его в C#. Если вы это сделаете, отправьте обратно рабочий класс C#, и я обновлю мой.:-)

Версия C#

public class RawPrinterHelper
{
    // Structure and API declarions:
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DOCINFOW
    {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pDocName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pOutputFile;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pDataType;
    }

    [DllImport("winspool.Drv", EntryPoint = "OpenPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool OpenPrinter(string src, ref IntPtr hPrinter, Int32 pd);
    [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool ClosePrinter(IntPtr hPrinter);
    [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, ref DOCINFOW pDI);
    [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndDocPrinter(IntPtr hPrinter);
    [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartPagePrinter(IntPtr hPrinter);
    [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndPagePrinter(IntPtr hPrinter);
    [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, ref Int32 dwWritten);

    // 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 static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
    {
        IntPtr hPrinter = default(IntPtr);
        // The printer handle.
        Int32 dwError = default(Int32);
        // Last error - in case there was trouble.
        DOCINFOW di = default(DOCINFOW);
        // Describes your document (name, port, data type).
        Int32 dwWritten = default(Int32);
        // The number of bytes written by WritePrinter().
        bool bSuccess = false;
        // Your success code.

        // Set up the DOCINFO structure.
        var _with1 = di;
        _with1.pDocName = "My Visual Basic .NET RAW Document";
        _with1.pDataType = "RAW";
        // Assume failure unless you specifically succeed.
        bSuccess = false;
        if (OpenPrinter(szPrinterName, ref hPrinter, 0))
        {
            if (StartDocPrinter(hPrinter, 1, ref _with1))
            {
                if (StartPagePrinter(hPrinter))
                {
                    // Write your printer-specific bytes to the printer.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }
        // If you did not succeed, GetLastError may give more information
        // about why not.
        if (bSuccess == false)
        {
            dwError = Marshal.GetLastWin32Error();
        }
        return bSuccess;
    }
    // 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 static bool SendFileToPrinter(string szPrinterName, string szFileName)
    {
        // Open the file.
        using (FileStream fs = new FileStream(szFileName, FileMode.Open))
        {
            // Create a BinaryReader on the file.
            BinaryReader br = new BinaryReader(fs);
            // Dim an array of bytes large enough to hold the file's contents.
            byte[] bytes = new byte[fs.Length + 1];
            bool bSuccess = false;
            // Your unmanaged pointer.
            IntPtr pUnmanagedBytes = new IntPtr(0);
            int 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;
        }
    }
    // SendFileToPrinter()

    // When the function is given a string and a printer name,
    // the function sends the string to the printer as raw bytes.
    public static bool SendStringToPrinter(string szPrinterName, string szString)
    {
        IntPtr pBytes = default(IntPtr);
        Int32 dwCount = default(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;
    }

}

public class CashDrawer
{
    public static void OpenCashDrawer(string printerName)
    {
        RawPrinterHelper.SendStringToPrinter(printerName, Globals.drawerCode);
    }
}
public static class Globals
{
    public static string fullPaperCutCode = Convert.ToChar(27).ToString() + Convert.ToChar(109).ToString();
    public static string drawerCode = Convert.ToChar(27).ToString() + Convert.ToChar(112).ToString() + Convert.ToChar(48).ToString() + Convert.ToChar(55).ToString() + Convert.ToChar(121).ToString();        
    public static string partialPaperCutCode = Convert.ToChar(27).ToString() + Convert.ToChar(105).ToString();
}
Другие вопросы по тегам