我的服务将报告转换为字节数组,并使用以下代码传递给客户端(wpf app):
byte[] bytes = renderer.ServerReport.Render("PDF", deviceInfo, out mimeType, out encoding, out extension, out streamids, out warnings);
其中renderer是Microsoft.Reporting.Webforms.ReportViewer的一个实例。这里有一个问题:编码输出参数返回null,因此无法找到有关编码的信息。
UI必须以静默方式将此字节数组打印到打印机。可以将此字节数组直接发送到打印机,而不是将其转换回UI中的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;
}
}
答案 0 :(得分:2)
是的,这不行。您使用此代码绕过打印机驱动程序,您必须使用您使用的特定打印机的打印机控制语言生成打印命令。 PCL和Postscript是常见的打印机控制语言。但无论如何,制造商通常会创建自己的定制品种。
看起来您正在发送PDF,我不知道任何使用PDF作为其本机控制语言的打印机。也许这样的打印机存在,显然你所拥有的打印机不存在。我无法猜到为什么你在服务中使用Webforms类,很难提供替代方案。从服务打印通常是一个坏主意,打印机驱动程序非常乐意提出“尽快更换碳粉”提示。在隐形桌面上显示,您无法找出文档无法打印的原因。
答案 1 :(得分:1)
我保留了初始实现,我将PDF文件发送到打印机,因为直接向打印机发送字节不起作用。
答案 2 :(得分:0)
我在这里玩游戏有点晚了,但是自从第一次提出这个问题以来已经过去了一段时间,说明您无法将 PDF 直接发送到打印机的回答现在不太正确。很多情况下可以使用System.IO文件拷贝将PDF文件直接发送到UNC打印机队列(只要打印机支持)
示例:File.Copy(pathToAPDFFileYouWantPrinted, @"\\fserverprint\printerName");
我知道这很管用,因为我一直在使用它。它非常快。问题是您需要先将字节数组写入文件,然后再将其复制到打印机。
虽然这不能满足 OP 的字节数组方法,但是一旦您将字节数组作为 PDF 格式使用字节数组/发送到打印机方法,实际上只需两行代码。
File.WriteAllBytes(pathToPDFFileYouWantPrinted, output);
File.Copy(pathToAPDFFileYouWantPrinted, @"\\fserverprint\printerName");
我最近尝试了字节数组方法,但它不起作用。你会得到这个错误:System.NotSupportedException: 'FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr.'