Coupons.com通过用户安装的本地二进制文件来提供此功能。我希望避免这种方式。
SmartSource.com通过Java小程序实现:
有人知道是如何实现的吗?我浏览了一下Java API,没有发现任何可以区分实体和虚拟打印机的东西,除非看打印机名称(这种方式容易误判)。如果能在Java中实现就更好了,因为我已经知道如何编写Java小程序。如果不行,Flash或Silverlight有办法吗?
谢谢。
好的,这是我迄今为止找到的(这并不是详尽无遗的测试,但这是一个有趣的问题需要试图解决)。看起来通过查看PrinterJob类中的validatePage()方法可能会有所帮助。如果打印作业是虚拟的,那么任何尝试设置页面的ImageableArea都将始终返回与默认页面的ImageableArea完全相等的值,而尝试对真实打印机执行相同操作将返回略小的值(以考虑打印机机械固定纸张的边缘)。对于这个问题有用的是,如果在调用validate之前只询问打印机的默认特性,您会得到一个乐观的结果,如果将其与经过验证的响应进行比较,则可以进行简单的if测试。我已经为此编写了一些代码,似乎可以处理桌面上的图像打印机和真实打印机(再次强调,这不是详尽无遗的,但它可以作为一个起点)
import java.awt.print.*;
import javax.print.PrintService;
import javax.print.attribute.Attribute;
public class DetectFilePrinter {
public static void main(String[] args) {
PrinterJob job = PrinterJob.getPrinterJob();
PrintService printer = job.getPrintService();
System.out.println("Printer Name:"+printer.getName());
System.out.println(printer.toString());
PageFormat page = job.defaultPage();
double default_width = page.getWidth();
double default_height = page.getHeight();
Paper paper = new Paper();
paper.setImageableArea(0, 0, Double.MAX_VALUE, Double.MAX_VALUE);
page.setPaper(paper);
PageFormat fixed_page = job.validatePage(page);
double fixed_width = fixed_page.getImageableWidth();
double fixed_height = fixed_page.getImageableHeight();
//So far all of my tested "image printers" return the same
//height and width after calling validatePage()
if(default_height == fixed_height && default_width == fixed_width) {
System.out.println("This looks like a \"image printer\"");
} else {
System.out.println("This looks like a \"real printer\"");
}
}
}
正如你所说,似乎有一些方法可以获取有关打印机的一些信息:
javax.print.attribute.standard.PrinterMakeAndModel
看起来很有前途。
禁止在任何打印机上使用文件:目标,并在打印机制造商和型号中包含单词 PDF
的任何打印机上打印,根据this list of virtual print software,这可能涵盖了90%的情况。实际上,您不太可能遇到单词 PDF 的误报。
如果此功能不完美,您的客户不太可能注意到;您的竞争对手也很可能有一些可怕的修补程序,因为他们同样清楚,这个功能更多是“安全剧院”,而不是实际安全。
我知道在Win32上很容易实现。有一个称为PRINTER_INFO_2的结构体,其中有一个名为pPortName的字段。您可以将其与字符串"FILE"进行比较,以获取与"FILE"端口连接的所有队列。您还可以类似地添加更多的解析逻辑以检测其他虚拟打印机。当您使用打印机句柄调用GetPrinter时,Windows将填充此结构体。现在的问题是如何在.NET中完成它。我看到了一种使用marshalling的方法。我在http://vbcity.com/forums/t/66183.aspx看到了一些代码片段。您还可以查看使用pInvoke的C#互操作http://pinvoke.net/default.aspx/Structures/PRINTER_INFO_2.html。
希望这能帮到你。