Impressão utilizando spool do windows C#
Este método é bastante utilizado para impressoras não fiscais, pois com ele se tem um envio genérico para o spool do windows,
não dependendo de DLLs de terceiros.
Algumas vantagens de se utilizar o spool são:
- O windows gerencia, então caso seja enviado conteúdo para impressão e a impressora esteja desligada, é só liga-la
que a impressão será realizada.
- Caso acabe o papel no meio da impressão, pode-se colocar mais que a impressão continuará de onde parou.
- A fila de impressão também é gerenciada pelo windows
Criei dois métodos para facilitar a chamada pelo aplicativo, um publico que será o método chamado em qualquer lugar da aplicação
e um privado para ninguém ter acesso a ele sem necessidade.
Mas antes disso precisamos criar uma classe que será a estrutura do documento enviado.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private class DocInfoA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
Depois importaremos os métodos do spool que iremos utilizar.
//Abrir os trabalhos na impressora
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
//Fechar a comunicação com a impressora
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
//Abrir o documento que será impresso
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
//Fechar o documento
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool EndDocPrinter(IntPtr hPrinter);
//Abrir uma página dentro do documento
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool StartPagePrinter(IntPtr hPrinter);
//Encerrar página
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool EndPagePrinter(IntPtr hPrinter);
//Enviar texto para a página aberta
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
private bool EnviaBytesParaImpressora(IntPtr pBytes, Int32 tamanhoTexto)
{
Int32 dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DocInfoA di = new DocInfoA();
bool retorno = false;
try
{
//pDocName = Nome do documento, pode ser o nome de sua preferência
di.pDocName = "Impressora Nao Fiscal";
di.pDataType = "RAW";
//Inicia comunicação com a impressora
if (OpenPrinter(NomeImpressora.Normalize(), out hPrinter, IntPtr.Zero))
{
//Abre o documento
if (StartDocPrinter(hPrinter, 1, di))
{
//Insere uma página
if (StartPagePrinter(hPrinter))
{
//Envia o conteúdo para impressora
retorno = WritePrinter(hPrinter, pBytes, tamanhoTexto, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
else
{
retorno = false;
}
}
//Caso algum problema ocorra a comunicação com a impressora é fechada para não ficar ocupando-a
catch
{
ClosePrinter(hPrinter);
}
return retorno;
}
public bool EnviaStringImpressora(string texto)
{
IntPtr pBytes;
Int32 tamanhoTexto;
bool retorno = false;
tamanhoTexto = texto.Length;
//carrega o ponteiro para a string na memória
pBytes = Marshal.StringToCoTaskMemAnsi(texto);
retorno = EnviaBytesParaImpressora(pBytes, tamanhoTexto);
//Limpa o ponteiro da memória
Marshal.FreeCoTaskMem(pBytes);
return retorno;
}