2011-06-09 319 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

相關問題