cpp

Cancelar trabajo de impresión con C++

En este post te quiero compartir un código de C++ para listar y cancelar trabajos de impresión de la cola de impresión de una impresora en Windows.

Con el código C++ vamos a usar la API de Windows (win32) con EnumJobs para obtener los trabajos de impresión de una impresora determinada, y después, opcionalmente, podremos cancelar ese trabajo con SetJob ya sea basándonos en el índice, usuario o cualquier otro dato del trabajo.

Abriendo impresora y listando trabajos

Comenzamos obteniendo un manejador de la impresora a partir de su nombre:

HANDLE manejadorImpresora = NULL;
PRINTER_DEFAULTSW pd = {nullptr, nullptr, PRINTER_ACCESS_USE};
if (!OpenPrinterW(const_cast<LPWSTR>(nombreImpresora.c_str()), &manejadorImpresora, &pd))
{
    std::wcerr << L"Error abriendo impresora " << nombreImpresora << std::endl;
    return;
}

Luego enumeramos los trabajos de impresión:

DWORD trabajos = 0, cantidadBytes = 0;
EnumJobsW(manejadorImpresora, 0, 0xFFFFFFFF, 1, nullptr, 0, &cantidadBytes, &trabajos);
if (cantidadBytes <= 0)
{

    std::wcout << L"Cola vacia" << std::endl;
    return;
}

Si hay trabajos, los recorremos:

auto trabajoDeImpresion = (JOB_INFO_1W *)malloc(cantidadBytes);
if (trabajoDeImpresion && EnumJobsW(manejadorImpresora, 0, 0xFFFFFFFF, 1, (LPBYTE)trabajoDeImpresion, cantidadBytes, &cantidadBytes, &trabajos))
{
    for (DWORD indice = 0; indice < trabajos; ++indice)
    {
        std::wcout << L"Trabajo " << trabajoDeImpresion[indice].JobId << L":" << std::endl;
        std::wcout << L"  Documento: "
                    << (trabajoDeImpresion[indice].pDocument ? trabajoDeImpresion[indice].pDocument : L"(Sin nombre)")
                    << std::endl;
        std::wcout << L"  Propietario: "
                    << (trabajoDeImpresion[indice].pUserName ? trabajoDeImpresion[indice].pUserName : L"(Desconocido)")
                    << std::endl;
        std::wcout << L"  Páginas impresas: " << trabajoDeImpresion[indice].PagesPrinted
                    << L" de " << trabajoDeImpresion[indice].TotalPages << std::endl;
        std::wcout << L"  Estado: " << trabajoDeImpresion[indice].Status << std::endl;
        // Y la siguiente línea lo cancela con JOB_CONTROL_CANCEL
        // Puedes tener un if y comprobar el índice, pUserName, etcétera
        SetJob(manejadorImpresora, trabajoDeImpresion[indice].JobId, 0, nullptr, JOB_CONTROL_CANCEL);
    }
}

Cancelar trabajo de impresión

La línea que cancela el trabajo de impresión es SetJob con la opción JOB_CONTROL_CANCEL y ya está dentro del ciclo que te mostré en el apartado anterior:

SetJob(manejadorImpresora, trabajoDeImpresion[indice].JobId, 0, nullptr, JOB_CONTROL_CANCEL);

De hecho no es obligatorio que imprimas los datos de los trabajos pendientes. También puedes hacer un if revisando el id, usuario, etcétera para saber si deberías cancelar el trabajo de impresión.

Código completo

El código completo queda como se ve a continuación. He encerrado todo el comportamiento en una función que puedes invocar desde el main. Dicha función recibe el nombre de la impresora tal y como aparece en el panel de control:

#include <windows.h>
#include <iostream>
#include <string>

void imprimirTrabajosYCancelar(const std::wstring &nombreImpresora)
{
    HANDLE manejadorImpresora = NULL;
    PRINTER_DEFAULTSW pd = {nullptr, nullptr, PRINTER_ACCESS_USE};
    if (!OpenPrinterW(const_cast<LPWSTR>(nombreImpresora.c_str()), &manejadorImpresora, &pd))
    {
        std::wcerr << L"Error abriendo impresora " << nombreImpresora << std::endl;
        return;
    }
    DWORD trabajos = 0, cantidadBytes = 0;
    EnumJobsW(manejadorImpresora, 0, 0xFFFFFFFF, 1, nullptr, 0, &cantidadBytes, &trabajos);
    if (cantidadBytes <= 0)
    {

        std::wcout << L"Cola vacia" << std::endl;
        return;
    }

    auto trabajoDeImpresion = (JOB_INFO_1W *)malloc(cantidadBytes);
    if (trabajoDeImpresion && EnumJobsW(manejadorImpresora, 0, 0xFFFFFFFF, 1, (LPBYTE)trabajoDeImpresion, cantidadBytes, &cantidadBytes, &trabajos))
    {
        for (DWORD indice = 0; indice < trabajos; ++indice)
        {
            std::wcout << L"Trabajo " << trabajoDeImpresion[indice].JobId << L":" << std::endl;
            std::wcout << L"  Documento: "
                       << (trabajoDeImpresion[indice].pDocument ? trabajoDeImpresion[indice].pDocument : L"(Sin nombre)")
                       << std::endl;
            std::wcout << L"  Propietario: "
                       << (trabajoDeImpresion[indice].pUserName ? trabajoDeImpresion[indice].pUserName : L"(Desconocido)")
                       << std::endl;
            std::wcout << L"  Páginas impresas: " << trabajoDeImpresion[indice].PagesPrinted
                       << L" de " << trabajoDeImpresion[indice].TotalPages << std::endl;
            std::wcout << L"  Estado: " << trabajoDeImpresion[indice].Status << std::endl;
            // Y la siguiente línea lo cancela con JOB_CONTROL_CANCEL
            // Puedes tener un if y comprobar el índice, pUserName, etcétera
            SetJob(manejadorImpresora, trabajoDeImpresion[indice].JobId, 0, nullptr, JOB_CONTROL_CANCEL);
        }
    }
    free(trabajoDeImpresion);
    ClosePrinter(manejadorImpresora);
}

int main()
{
    // Nombre de tu impresora tal y como aparece en el panel de control
    std::wstring nombreImpresora = L"POS58 Printer";
    imprimirTrabajosYCancelar(nombreImpresora);
    return 0;
}

Para compilarlo hay que pasar el parámetro -lwinspool así:

g++ main.cpp -lwinspool -o cola_impresion.exe

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Resetear GOOJPRT PT-210 MTP-II (Impresora térmica)

El día de hoy vamos a ver cómo restablecer la impresora térmica GOOJPRT PT-210 a…

4 días hace

Proxy Android para impresora térmica ESC POS

Hoy voy a enseñarte cómo imprimir en una impresora térmica conectada por USB a una…

5 días hace

Android – Servidor web con servicio en segundo plano

En este post voy a enseñarte a programar un servidor web en Android asegurándonos de…

5 días hace

Copiar bytes de Golang a JavaScript con WebAssembly

Gracias a WebAssembly podemos ejecutar código de otros lenguajes de programación desde el navegador web…

2 meses hace

Imprimir PDF con Ghostscript en Windows de manera programada

Revisando y buscando maneras de imprimir un PDF desde la línea de comandos me encontré…

2 meses hace

Hacer pruebas en impresora térmica Bluetooth Android

Esta semana estuve recreando la API del plugin para impresoras térmicas en Android (HTTP a…

2 meses hace