Dicas sobre desenvolvimento de software, gestão e tributações

Rede Social

30 de setembro de 2015

Impressão utilizando spool do windows C#


Aqui vai uma forma de enviar string para a impressora utilizando o spool do windows.
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;
}

Um comentário:

  1. Mateus,

    Gostaria de agradecer a sua postagem!

    Sou iniciante e estava a algum tempo com dificuldades para enviar informações para a impressora sem usar o PrintPage ou a DLL do fabricante da impressora.

    Muito Obrigado! Sua postagem funcionou perfeitamente me ajudou bastante!

    ResponderExcluir