Подтвердить что ты не робот

Сырая печать непосредственно на USB-принтер, минуя диспетчер очереди Windows

Я экспериментирую с термальным принтером Zebra TTP8200. Для моего приложения мне нужно непрерывно печатать следы типа плоттера, пока пользователь не нажмет кнопку остановки. У меня была игра с языком ZPL, и я могу успешно генерировать растровые данные и выгружать свою растровую линию (или несколько строк) за раз, вызывая ZPL как необработанные данные.

Я использую какой-то демонстрационный код Microsoft для вывода необработанных данных на принтер, и это отлично работает, запустите одну проблему: спулер. Оказывается, каждый раз, когда я вывожу некоторые данные с помощью кода MS rawprn.exe, он фактически буферизуется как задание на печать и затем передается на принтер. Это займет до 10 секунд, чтобы пройти через спулер, очевидно, слишком медленно. Отключение буферизации в драйвере не помогает, это просто означает, что программа зависает, когда задание передается через спулер, и печать завершается.

Есть ли способ обхода буферизации и вывода данных прямо на этот USB-принтер? До сих пор мои исследования не обнаружили ничего похожего на Windows API. В идеале я бы хотел использовать принтер, как это был последовательный принтер, - откройте порт и запустите данные.

Большое спасибо заранее за любые подсказки!

4b9b3361

Ответ 1

Спасибо за комментарии.

После некоторого дополнительного поиска я нашел эту интересную статью об использовании функций принтера Windows, предоставляемых usbprint.sys. С небольшим взломом пример кода, похоже, сработал. Я думаю, что пройду этот маршрут.

В статье приведен окончательный код:

/* 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);
}

Еще раз спасибо за предложения.

Ответ 2

Если USB-принтер доступен как COM-порт, вы можете просто записать его на COM-порт. Как это, из подсказки DOS:

dir > com1

В предыдущем примере выводятся результаты команды dir на принтер.

Или, вот еще один пример:

copy file.txt com1

В предыдущем примере выводится содержимое file.txt на принтер.

Вывод корректно отформатированных данных ZPL будет сложнее обычного текста. Однако я получил это от Linux, используя Ruby (и команды Epson/ESC).

Ответ 3

Есть ли способ обхода буферизатора и вывода данных прямо к этому USB-принтер?

Да, абсолютно. Он встроен в большинство ОС, печать сырья через USB лишь немного менее очевидна, чем Ethernet и COM/LPT. Обратите внимание: многие приложения, такие как блокнот, не могут печатать необработанные, поэтому ваше приложение также должно поддерживать это.

  • Установите соответствующий драйвер для вашего USB-принтера. Проверьте свойства принтера, чтобы узнать, какой USB-порт он использует. Это может быть USB001 и т.д.
  • Используя устройства и принтеры, добавьте второй принтер. Локальный порт, выберите только что созданный порт (например, USB001). Примечание. В некоторых версиях Windows есть флажок для автоматического определения, если он там, снимите этот флажок.
  • Производитель: Generic, Printer: общий/только текст
  • Использовать драйвер, который в настоящее время установлен.
  • Дайте принтеру имя, которое отличает его от уже созданного, т.е. Zebra TTP8200 Raw.
  • Не сообщайте
  • Не печатайте тестовую страницу, завершайте

Теперь с помощью приложения с необработанной печатью используйте только что созданный принтер.

P.S. Эти инструкции также доступны здесь, с скриншотами, как часть учебника для печати с открытым исходным кодом Java с открытым исходным кодом. Проект также предоставляет учебные пособия для других платформ (Ubuntu, OS X).

http://qzindustries.com/TutorialRawWin

-Tres

Ответ 4

Вы должны попробовать метод, описанный в приведенной ниже ссылке. Это позволяет отправлять необработанные данные на принтер.

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