Как открыть кассовый ящик, который связан с чековым принтером с помощью 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();
}