2011-06-09 321 views
13

我正在试验Zebra TTP8200热敏打印机。对于我的应用程序,我需要连续打印绘图仪类型的迹线,直到用户点击停止按钮。我玩过ZPL语言,我可以成功地生成位图数据,并通过输出ZPL作为原始数据一次将我的位图转储出一行(或几行)。直接打印到USB打印机,绕过Windows假脱机程序

我使用一些Microsoft demo code输出原始数据到打印机,这很好,一个问题:一个问题:后台打印程序。事实证明,每当我使用MS rawprn.exe代码输出一些数据时,它实际上被假脱机为打印作业,然后传输到打印机。这需要10秒才能通过假脱机程序,显然太慢了。在驱动程序中禁用假脱机程序并没有帮助,这只是意味着程序在作业通过假脱机程序并打印完成时挂起。

有没有办法绕过假脱机程序并将数据直接输出到此USB打印机?到目前为止,我的研究还没有发现任何可能在Windows API中寻找的东西。理想情况下,我希望能够像使用串行打印机一样使用打印机 - 打开端口并将数据传入。

非常感谢您提供任何提示!

+0

看看这有助于:http://stackoverflow.com/questions/4801049/programmatically-set-printer-to-bypass-the-windows-spooler – 2011-06-09 16:39:06

回答

-2

感谢您的意见。

经过一番更多的挖掘,我发现使用由usbprint.sys提供的Windows打印机功能this interesting article。有一些黑客入侵示例代码似乎有效。我想我会走这条路。

还有就是文章中给出的最终代码:您的建议,再次

/* Code to find the device path for a usbprint.sys controlled 
* usb printer and print to it 
*/ 

#include <usb.h> 
#include <usbiodef.h> 
#include <usbioctl.h> 
#include <usbprint.h> 
#include <setupapi.h> 
#include <devguid.h> 
#include <wdmguid.h> 

/* This define is required so that the GUID_DEVINTERFACE_USBPRINT variable is 
* declared an initialised as a static locally, since windows does not include it 
* in any of its libraries 
*/ 

#define SS_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 
static const GUID name \ 
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 

SS_DEFINE_GUID(GUID_DEVINTERFACE_USBPRINT, 0x28d78fad, 0x5a12, 0x11D1, 0xae, 
       0x5b, 0x00, 0x00, 0xf8, 0x03, 0xa8, 0xc2); 

void SomeFunctionToWriteToUSB() 
{ 
    HDEVINFO devs; 
    DWORD devcount; 
    SP_DEVINFO_DATA devinfo; 
    SP_DEVICE_INTERFACE_DATA devinterface; 
    DWORD size; 
    GUID intfce; 
    PSP_DEVICE_INTERFACE_DETAIL_DATA interface_detail; 

    intfce = GUID_DEVINTERFACE_USBPRINT; 
    devs = SetupDiGetClassDevs(&intfce, 0, 0, DIGCF_PRESENT | 
          DIGCF_DEVICEINTERFACE); 
    if (devs == INVALID_HANDLE_VALUE) { 
    return; 
    } 
    devcount = 0; 
    devinterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 
    while (SetupDiEnumDeviceInterfaces(devs, 0, &intfce, devcount, &devinterface)) { 
    /* The following buffers would normally be malloced to he correct size 
    * but here we just declare them as large stack variables 
    * to make the code more readable 
    */ 
    char driverkey[2048]; 
    char interfacename[2048]; 
    char location[2048]; 
    char description[2048]; 

    /* If this is not the device we want, we would normally continue onto the 
    * next one or so something like 
    * if (!required_device) continue; would be added here 
    */ 
    devcount++; 
    size = 0; 
    /* See how large a buffer we require for the device interface details */ 
    SetupDiGetDeviceInterfaceDetail(devs, &devinterface, 0, 0, &size, 0); 
    devinfo.cbSize = sizeof(SP_DEVINFO_DATA); 
    interface_detail = calloc(1, size); 
    if (interface_detail) { 
     interface_detail->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); 
     devinfo.cbSize = sizeof(SP_DEVINFO_DATA); 
     if (!SetupDiGetDeviceInterfaceDetail(devs, &devinterface, interface_detail, 
              size, 0, &devinfo)) { 
    free(interface_detail); 
    SetupDiDestroyDeviceInfoList(devs); 
    return; 
     } 
     /* Make a copy of the device path for later use */ 
     strcpy(interfacename, interface_detail->DevicePath); 
     free(interface_detail); 
     /* And now fetch some useful registry entries */ 
     size = sizeof(driverkey); 
     driverkey[0] = 0; 
     if (!SetupDiGetDeviceRegistryProperty(devs, &devinfo, SPDRP_DRIVER, &dataType, 
              (LPBYTE)driverkey, size, 0)) { 
    SetupDiDestroyDeviceInfoList(devs); 
    return; 
     } 
     size = sizeof(location); 
     location[0] = 0; 
     if (!SetupDiGetDeviceRegistryProperty(devs, &devinfo, 
              SPDRP_LOCATION_INFORMATION, &dataType, 
              (LPBYTE)location, size, 0)) { 
    SetupDiDestroyDeviceInfoList(devs); 
    return; 
     } 
     usbHandle = CreateFile(interfacename, GENERIC_WRITE, FILE_SHARE_READ, 
       NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | 
       FILE_FLAG_SEQUENTIAL_SCAN, NULL); 
     if (usbHandle != INVALID_HANDLE_VALUE) { 
    /* Now perform all the writing to the device ie. 
    * while (some condition) WriteFile(usbHandle, buf, size, &bytes_written); 
    */ 
    CloseHandle(usbHandle); 
     } 
    } 
    } 
    SetupDiDestroyDeviceInfoList(devs); 
} 

感谢。

+5

-1:在这个答案中没有代码,和一个死链接:(添加一些代码,我会将-1更改为+1! – 2014-10-27 18:37:57

2

如果USB打印机可用作COM端口,则只需写入COM端口即可。与此类似,在DOS提示符:

dir > com1 

前者例如将输出dir命令到打印机的结果。

或者,这里是另一个例子:

copy file.txt com1 

前者例子将输出的file.txt到打印机的内容。

输出格式正确的ZPL数据将比纯文本难。但是,我已经通过使用Ruby(和Epson/ESC命令)从Linux开始工作。

+0

你好泰迪,感谢这一点,它不会显示为COM端口。如果这样做,那么所有的事情都会像你所建议的那样简单!如果有一个替代驱动程序使其成为一个虚假的串行接口,那将会很不错。 – 2011-06-12 11:40:44

+0

制造商网站称打印机支持并行打印。您可以写入LPT1端口,就像COM端口一样。在我的示例中,只需将COM1替换为LPT1即可。 – Teddy 2011-06-12 14:01:18

+0

嗨泰迪,我很确定我的版本只有USB(但是我会在明天回来的时候检查它)。对于这个应用程序,我们实际上将使用PC的并行端口用于其他设备,我宁愿不使用附加的PCI卡 - 这看起来太过于90年代了! – 2011-06-12 19:31:36

0

您应该尝试下面链接中概述的方法。这使您可以将原始数据发送到打印机。

http://support.microsoft.com/kb/322091/en-us

+0

谢谢,这基本上只是我在OP中包含的链接的C#版本。 – 2011-06-20 08:52:16

2

有没有办法绕过假脱机程序并输出数据直接到这个 USB打印机?

是的,绝对。它内置于大多数操作系统中,通过USB打印原始数据只比以太网和COM/LPT少一些。请注意,许多应用程序(如记事本)无法打印原始文件,因此您的应用程序也需要支持此功能。

  1. 为您的USB打印机安装适当的驱动程序。检查打印机属性以查看它使用的是哪个USB端口。它可能是USB001等。
  2. 使用设备和打印机,添加第二台打印机。本地端口,选择刚刚创建的端口(即USB001)注意:某些版本的Windows有自动检测的复选框,如果有,请取消选中此项。
  3. 制造商:通用,打印机:通用/文本仅
  4. 使用当前安装
  5. 给打印机,从已经创建了一个,即斑马TTP8200生相区别的名称驱动程序。
  6. 不要用你的原始打印应用程序共享
  7. 不要打印测试页,完成

现在,使用新创建的打印机。

P.S. 这些指令也可以在这里获得,并带有屏幕截图,作为Java开源原始打印教程的一部分。该项目也为其他平台(Ubuntu,OS X)提供了教程。

http://qzindustries.com/TutorialRawWin

-Tres

相关问题