Отправка байтового массива на принтер напрямую - PullRequest
3 голосов
/ 17 августа 2010

Мой сервис преобразует отчет в байтовый массив и передает его клиенту (приложение wpf), используя следующий код:

byte[] bytes = renderer.ServerReport.Render("PDF", deviceInfo, out mimeType, out encoding, out extension, out streamids, out warnings);

где средство визуализации является экземпляром Microsoft.Reporting.Webforms.ReportViewer. Здесь есть проблема: выходной параметр кодирования возвращает ноль, поэтому не удалось найти информацию о кодировке.

Пользовательский интерфейс должен печатать этот байтовый массив без вывода сообщений на принтер. Можно ли отправить этот байтовый массив непосредственно на принтер вместо преобразования его обратно в файл PDF в пользовательском интерфейсе и последующей печати?

Я на самом деле пробовал что-то похожее ниже, посмотрев на ссылку msdn, но это печать странных символов на очень многих страницах, когда реальный отчет - одна или две страницы. В интернете меньше информации о функциях winspool dll, поэтому не уверен, где я ошибаюсь.

Любые идеи высоко ценятся.

public class RawPrintHelper
{
     //Structure and API declarions:
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public class DOCINFOA
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public string pDocName;
        [MarshalAs(UnmanagedType.LPStr)]
        public string pOutputFile;
        [MarshalAs(UnmanagedType.LPStr)]
        public string pDataType;
    }
    [DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

    [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool ClosePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartDocPrinter", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

    [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndDocPrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out 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, false on failure.
    public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
    {
        Int32 dwError = 0, dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        DOCINFOA di = new DOCINFOA();
        bool bSuccess = false; // Assume failure unless you specifically succeed.

        di.pDocName = "My C#.NET RAW Document";
        di.pDataType = "RAW";

        // Open the printer.
        if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
        {
            // Start a document.
            if (StartDocPrinter(hPrinter, 1, di))
            {
                // Start a page.
                if (StartPagePrinter(hPrinter))
                {
                    // Write your bytes.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out 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;
    }

}

Ответы [ 2 ]

2 голосов
/ 17 августа 2010

Да, это не может работать.Вы обходите драйвер принтера с этим кодом, вам придется генерировать команды печати, используя язык управления принтером конкретного принтера, который вы используете.PCL и Postscript являются общими языками управления принтером.Но ничего не происходит, производители часто создают свои собственные варианты.

Похоже, вы отправляете PDF, я не знаю ни одного принтера, который использует PDF в качестве родного языка управления.Может быть, такой принтер существует, очевидно, тот, который у вас нет.Я не могу догадаться, почему вы используете класс Webforms в сервисе, трудно предоставить альтернативу.Печать из службы - это вообще плохая идея, драйверы принтеров с радостью выдают подсказки «Скоро смените тонер».Показанный на невидимом рабочем столе, у вас нет возможности узнать, почему документ не печатается.

1 голос
/ 21 января 2011

Я сохранил свою первоначальную реализацию, где отправлял файл PDF на принтер, так как отправка байтов непосредственно на принтер не работала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...