【问题标题】:Portable way to determining of printer is physical or virtual确定打印机的便携式方式是物理的还是虚拟的
【发布时间】:2011-02-25 01:13:58
【问题描述】:

我的网站需要直接到打印机的功能,能够区分物理打印机和虚拟打印机(文件)。

Coupons.com 通过必须由用户安装的本机二进制文件提供此功能。我宁愿避免这种情况。

SmartSource.com 通过 Java 小程序实现:

有人知道这是怎么做到的吗?我对 Java API 进行了一些研究,除了查看名称(似乎容易识别错误)之外,没有看到任何可以让您确定物理与虚拟的东西。能够用 Java 来做会很好,因为我已经知道如何编写 Java 小程序了。如果做不到这一点,有没有办法在 Flash 或 Silverlight 中做到这一点?

提前致谢。

编辑: Jason Sperske 获得了当之无愧的赏金,他提出了一个优雅的解决方案。感谢那些分享想法的人,以及那些真正研究过 SmartSource.com 解决方案的人(比如 Adrian)。

【问题讨论】:

  • 你为什么要做这样的事情?你想解决什么问题?
  • 以相反的顺序回答您的问题:(2) 我需要尝试将打印限制为仅一份。 (1) 我需要这样做的原因与 Coupons.com、SmartSource.com 和其他在线优惠券渠道的原因相同:提供这些优惠券的制造商不希望人们能够轻松打印多份优惠券。是的,我知道:任何有半脑的人都可以将物理打印机的输出带到复印机,但是这个特殊的障碍(直接到打印机,不允许文件打印机)现在在这些其他网站上是标准的,所以制造商期望它(理性或不是)。
  • 那么您基本上要问的是“我怎样才能在 Java/flash/silverlight 中构建像 failblog.org/2008/03/13/toll-gate-fail 这样的无用收费站”?我为您接受如此毫无意义的任务感到抱歉,也为您的雇主的无知和缺乏常识感到抱歉。你有机会教育他们吗?
  • 我的雇主正在尝试与制造商签约以提供优惠券,这反过来又可以让我们获得更多的风险投资。制造商是要求这种减速带的人,我们无法告诉他们这是愚蠢的;与他们一起工作的其他人都会把它交给他们。 | 从技术角度来看,我并不真正关心为什么,我只想知道如何。 SmartSource.com 是用 Java 做的,所以它一定是可能的。怎么样?
  • 两个建议 - 让第三方反编译该小程序并笼统地告诉您它是如何工作的 - 可以理解原始 JVM 指令,并且它必须包含解密字符串的代码。或者在每张优惠券上打印一个唯一的条形码,并为您的客户提供网络服务,使他们能够确保每张优惠券只兑换一次——通过提供真正的安全性,让您与只提供安全剧院的竞争对手区分开来。

标签: java silverlight flash printing hardware


【解决方案1】:

好的,这就是我目前所发现的(无论如何,这不是一个详尽的测试,但尝试解决它是一个有趣的问题)。通过查看 PrinterJob 类中的 validatePage() 方法的工作原理,似乎可能会有一些帮助。似乎如果打印机作业是虚拟的,那么设置页面的 ImageableArea 的任何尝试将始终返回一个与默认页面 ImageableArea 完全相同的值,而对真实打印机进行相同的尝试将返回稍小的值(考虑到纸张的边缘被打印机机械师握住。对于这个问题有帮助的是,如果您只是在调用验证之前询问打印机它的默认特征,您会得到一个乐观的结果,如果您将其与经过验证的响应进行比较,您可以执行简单的 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\"");
    }
  }
}

【讨论】:

  • 杰森,你就是那个男人。感谢一个非常聪明的解决方案。感谢您超越职责范围。
  • 顺便说一句:我写了一点test applet,在我女朋友的机器上得到了错误检测——微软OneNote。我得玩一下这个。
  • 有趣,如果您想使用赏金来尝试获得更好的答案,请随时取消选择我的答案。
【解决方案2】:

正如您所说,似乎有一些方法可以收集有关打印机的一些信息:

javax.print.attribute.standard.PrinterMakeAndModel 看起来很有希望。

不允许文件:任何打印机上的目的地,以及在打印机品牌和型号中使用单词PDF 打印到任何打印机可能会涵盖由this list of virtual print software 判断的90% 的情况。实际上,您也不会在 PDF 一词上遇到误报。

如果此功能不完美,您的客户可能不会注意到;您的竞争对手可能也有一些可怕的组合,因为他们也知道这个功能更像是“安全剧院”而不是真正的安全。

【讨论】:

    【解决方案3】:

    我知道如何在 Win32 上轻松完成。有一个名为 PRINTER_INFO_2 的结构,其中有一个名为 pPortName 的字段。您可以将其与字符串“FILE”进行字符串比较,并获取连接到“FILE”端口的所有队列。并且您可以类似地添加更多解析逻辑来检测其他虚拟打印机。当您使用打印机句柄调用 GetPrinter 时,Windows 会填充此结构。现在的问题是如何在.NET 中做到这一点。我看到了一种使用编组的方法。我在http://vbcity.com/forums/t/66183.aspx 中看到了一些代码 sn-ps。您还可以使用 pInvoke 查看 C# 互操作。 http://pinvoke.net/default.aspx/Structures/PRINTER_INFO_2.html

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2011-03-27
      • 1970-01-01
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多