79162136

Date: 2024-11-06 10:19:38
Score: 1.5
Natty:
Report link

I managed to resolve the issue by changing my approach entirely. Initially, I was using System.Drawing.Printing, but this caused problems when running the application through Task Scheduler on a server without a graphical environment. Instead, I switched to using native Windows API functions to send the file directly to the printer in RAW mode, bypassing the need for a graphical interface:

[DllImport("winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true)]
public static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);

[DllImport("winspool.drv", EntryPoint = "ClosePrinter")]
public static extern bool ClosePrinter(IntPtr hPrinter);

[DllImport("winspool.drv", EntryPoint = "StartDocPrinterA", SetLastError = true)]
public static extern bool StartDocPrinter(IntPtr hPrinter, int level, ref DOCINFOA pDocInfo);

[DllImport("winspool.drv", EntryPoint = "EndDocPrinter")]
public static extern bool EndDocPrinter(IntPtr hPrinter);

[DllImport("winspool.drv", EntryPoint = "StartPagePrinter")]
public static extern bool StartPagePrinter(IntPtr hPrinter);

[DllImport("winspool.drv", EntryPoint = "EndPagePrinter")]
public static extern bool EndPagePrinter(IntPtr hPrinter);

[DllImport("winspool.drv", EntryPoint = "WritePrinter", SetLastError = true)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, int dwCount, out int dwWritten);

[StructLayout(LayoutKind.Sequential)]
public struct DOCINFOA
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string pDocName;
    [MarshalAs(UnmanagedType.LPStr)]
    public string pOutputFile;
    [MarshalAs(UnmanagedType.LPStr)]
    public string pDataType;
}

public static bool QueueDocument(string printerName, string filePath)
{
    bool result = false;
    IntPtr pBytes = IntPtr.Zero; // Pointer to the data to send to the printer
    byte[] fileBytes = File.ReadAllBytes(filePath);

    if (OpenPrinter(printerName, out var hPrinter, IntPtr.Zero))
    {
        var docInfo = new DOCINFOA
        {
            pDocName = Path.GetFileName(filePath),
            pOutputFile = null,
            pDataType = "RAW"
        };
        try
        {
            if (StartDocPrinter(hPrinter, 1, ref docInfo) && StartPagePrinter(hPrinter))
            {
                pBytes = Marshal.AllocHGlobal(fileBytes.Length);
                Marshal.Copy(fileBytes, 0, pBytes, fileBytes.Length);
                result = WritePrinter(hPrinter, pBytes, fileBytes.Length, out _);
            }
        }
        catch (Exception ex)
        {
            SentrySdk.CaptureException(ex);
        }
        finally
        {
            if (pBytes != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(pBytes);
            }
            EndPagePrinter(hPrinter);
            EndDocPrinter(hPrinter);
            ClosePrinter(hPrinter);
        }
    }
    else
    {
        SentrySdk.CaptureMessage("Printer connection error", SentryLevel.Error);
    }
    return result;
}

This approach bypasses the issues I faced with System.Drawing.Printing and works smoothly with Task Scheduler, as it doesn’t rely on a graphical interface.

Note: While this solution works well for the current case, there may still be room for optimization in terms of code readability and performance. For now, it works fine, but I may revisit it later to improve its efficiency and clarity.

Hope this helps anyone else facing similar issues!

Reasons:
  • Whitelisted phrase (-1): Hope this helps
  • Long answer (-1):
  • Has code block (-0.5):
  • Me too answer (2.5): facing similar issue
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: lucario