C++ win32 USB打印机开发

前言

      Windows系统 打印机连接电脑,windows会自动更新硬件驱动来识别硬件;  正规的打印机打印机一般都有自己的官方驱动;打印机一般都支持ESC/POS指令。所以小票打印一般可以采取两种模式:1、基于硬件驱动;2、基于打印机驱动。

     本文只做一个实现上的抛砖引玉。

基于打印驱动

流程:应用软件=>打印驱动=>设备驱动=>打印设备

开发: 

 1 : 获得本地打印驱动

struct  PrintInfo
{
    BOOL            m_bisPrintPage;
    string          sDeviceName;
    string          sPortName;
    string          sShareName;
    string          sLoction;
    string          sPaperType;
    int             nWidthMin;
    bool            bisPrint;
    PrintInfo()
    {
      m_bisPrintPage = FALSE;
      sDeviceName = "";
      sPortName = "";
      sShareName = "";
      sLoction = "";
      sPaperType = "";
      nWidthMin = 0;
      bisPrint = FALSE;
    }

};
typedef  vector<PrintInfo> PrintInfo_Ary;
int   GetLocalPrinterDrivers(PrintInfo_Ary &Drivers)
{
    DWORD        Flags =  PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL; //local printers
    DWORD        cbBuf;
    DWORD        pcReturned;
    DWORD        index;
    DWORD        Level = 2;
    CHAR        Name[500];
    LPPRINTER_INFO_2A pPrinterEnum = NULL;

    memset(Name, 0, sizeof(CHAR)* 500);
    ::EnumPrintersA(Flags, Name, Level, NULL, 0, &cbBuf, &pcReturned);
    pPrinterEnum = (LPPRINTER_INFO_2A)LocalAlloc(LPTR, cbBuf + 4);
    if (!pPrinterEnum)
    {
        goto clean_up;
    }

    if (!EnumPrintersA(
        Flags,                            // DWORD Flags, printer object types 
        Name,                            // LPTSTR Name, name of printer object 
        Level,                            // DWORD Level, information level 
        (LPBYTE)pPrinterEnum,            // LPBYTE pPrinterEnum, printer information buffer 
        cbBuf,                            // DWORD cbBuf, size of printer information buffer
        &cbBuf,                            // LPDWORD pcbNeeded, bytes received or required 
        &pcReturned)                    // LPDWORD pcReturned number of printers enumerated 
        )
    {
        goto clean_up;
    }
    if (pcReturned > 0)
    {
        for (index = 0; index < pcReturned; index++)
        {
            PrintInfo DeviceDate;
            if ((pPrinterEnum + index)->pPrinterName != NULL)
                DeviceDate.sDeviceName = (pPrinterEnum + index)->pPrinterName;
            else
                DeviceDate.sDeviceName ="";
            
            if ((pPrinterEnum + index)->pPortName != NULL)
                DeviceDate.sPortName = (pPrinterEnum + index)->pPortName;
            else
                DeviceDate.sPortName = "";
        
            if ((pPrinterEnum + index)->pShareName != NULL)
                DeviceDate.sShareName = (pPrinterEnum + index)->pShareName;
            else
                DeviceDate.sShareName = "";
    
            if ((pPrinterEnum + index)->pLocation != NULL)
                DeviceDate.sLoction = (pPrinterEnum + index)->pLocation;
            else
                DeviceDate.sLoction = "";
            
            if ((pPrinterEnum + index)->pDevMode)
            {
                DeviceDate.nWidthMin = (pPrinterEnum + index)->pDevMode->dmPaperWidth;
                DeviceDate.sPaperType = (char*)((pPrinterEnum + index)->pDevMode->dmFormName);
            }
            //DeviceDate.nWidthMin = (pPrinterEnum + index)->pDevMode->dmPaperWidth;
            //DeviceDate.sPaperType = (char*)((pPrinterEnum + index)->pDevMode->dmFormName);
            DWORD nstuse = (pPrinterEnum + index)->Status;
            DWORD Attributes = (pPrinterEnum + index)->Attributes;
            DeviceDate.m_bisPrintPage = BisConnectedA(nstuse, Attributes);
            Drivers.push_back(DeviceDate);

        }
    }
clean_up:
    LocalFree(LocalHandle(pPrinterEnum));
    return (int)Drivers.size();
}

2: 打开设备进行打印打开一个打印机驱动DriverName 是驱动名称

{
    HDC hdcPrint = CreateDC(NULL, DriverName, NULL, NULL);
HFONT Font =
CreateFont(32, 0, 0, 0, fontWeight, 0, 0, 0,
DEFAULT_CHARSET, OUT_TT_PRECIS,
CLIP_TT_ALWAYS, PROOF_QUALITY,VARIABLE_PITCH | FF_MODERN | 0x04,L"宋体");
//设置打印梯子
SelectObject(hdcPaint,Font);

LPCWSTR Lp
= L"task";
DOCINFO div={sizeof (DOCINFO),Lp};
    //编辑一个文档
    StartDoc(hdcPrint, &m_di);
    //编辑一个文档的一页
    StartPage(hdcPrint);
    RECT rect;
    rect.top = 0;
    rect.bottom = 200;
    rect.left = 0;
    rect.right = 380;
    DrawTextA(hdcPrint, "helleo world",13, &rect, DT_LEFT | DT_TOP | DT_EXPANDTABS | DT_NOPREFIX | DT_EDITCONTROL | DT_WORDBREAK | DT_EXTERNALLEADI    NG | DT_CALCRECT);
    DrawTextA(hdcPrint,"helleo world",13,&rect, DT_LEFT | DT_TOP | DT_EXPANDTABS | DT_NOPREFIX | DT_EDITCONTROL | DT_WORDBREAK | DT_EXTERNALLEADING    );
   //....
   //结束编辑页
   EndPage(hdcPrint);
   //结束整个文本编辑
   EndDoc(hdcPrint);
   CloseHandle(hdcPrint);
}

 

3: 总结,以上代码只做抛砖引玉,由于驱动都是GDI驱动,所以文字按照GDI绘制即可。

基于硬件驱动开发

流程: 应用软件=>设备驱动=>打印设备

简述: 很明显基于设备驱动开发,跳过了打印驱动层,这个优点是不需要关心打印驱动是否正常,是否需要配置端口。劣势,直接和打印机通信,基于(ESC)指令,这样增加了开发难度。

开发: 

1: 获得打印设备信息

#pragma once

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <vector>
#pragma comment (lib, "setupapi.lib")
const char DRIVER_NAME_USBPRINT[] = "USB 打印支持";
const char DRIVER_NAME_USBPRINT_EN[] = "USB Printing Support";

struct  deviceinfo {
    std::string  sdeviceid;
    std::string  sdesc;
    std::string  sdevicepath; 
    std::string  sdeviceshow;
    deviceinfo() {
        sdeviceid = "";
        sdesc = "";
        sdevicepath = "";
        sdeviceshow = "";
    }
};

std::vector<deviceinfo > g_printerdevices;
const GUID GUID_DEVINTERFACE_USB_HUB             = { 0xf18a0e88L, 0xc30c, 0x11d0, { 0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8 } };
const GUID GUID_DEVINTERFACE_USB_DEVICE          = { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3abf6f2dL, 0x71c4, 0x462a, { 0x8a, 0x92, 0x1e, 0x68, 0x61, 0xe6, 0xaf, 0x27 } };
const GUID GUID_USB_WMI_STD_DATA                 = { 0x4E623B20L, 0xCB14, 0x11D1, { 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2 } };
const GUID GUID_USB_WMI_STD_NOTIFICATION         = { 0x4E623B20L, 0xCB14, 0x11D1, { 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2 } };
const GUID USBPrinterGUID                        = { 0x4d36e979L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
//GUID__DEVINTERFACE_USB_DEVICE
int  GetUSBPrintDevices(const GUID guid)
{
    const GUID GUID_DEVINTERFACE_USB_DEVICE  = guid;
    const GUID* InterfaceGuid = &GUID_DEVINTERFACE_USB_DEVICE;

    // that contains all devices of a specified class
    HDEVINFO hDevInfo = SetupDiGetClassDevsA(InterfaceGuid,
                                             NULL, // Enumerator
                                             NULL,
                                             DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

    if (hDevInfo == INVALID_HANDLE_VALUE)
    {
        return 1;
    }

    SP_DEVINFO_DATA DeviceInfoData;
    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    PSP_DEVINFO_DATA pDeviceInfoData = &DeviceInfoData;

    DWORD MemberIndex;

    bool found_usb_printer_flag = false;

    for (MemberIndex = 0;
         SetupDiEnumDeviceInfo(hDevInfo,
                               MemberIndex,
                               pDeviceInfoData) == TRUE;
         MemberIndex++)
    {
        SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
        DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        PSP_DEVICE_INTERFACE_DATA pDeviceInterfaceData = &DeviceInterfaceData;

        DWORD RequiredSize;
        PDWORD pRequiredSize = &RequiredSize;

        DWORD InnerMemberIndex;
        for (InnerMemberIndex = 0; SetupDiEnumDeviceInterfaces(hDevInfo, 
                                         pDeviceInfoData,
                                         InterfaceGuid,
                                         InnerMemberIndex,
                                         pDeviceInterfaceData) == TRUE;
             InnerMemberIndex++)
        {
            
            DWORD DeviceInterfaceDetailDataSize = 0;
            BOOL first_call_result = SetupDiGetDeviceInterfaceDetailA(hDevInfo,
                                                                      pDeviceInterfaceData,
                                                                      NULL, // NULL DeviceInterfaceDetailData pointer
                                                                      0,    // DeviceInterfaceDetailDataSize of zero
                                                                      pRequiredSize,
                                                                      pDeviceInfoData);

            if (first_call_result == TRUE)
            {
                continue;
            }
            else 
            {
                DWORD first_call_error = GetLastError();
                if (first_call_error != ERROR_INSUFFICIENT_BUFFER)
                {
                    continue;
                }
                else
                {

                    CHAR* buffer = new CHAR[RequiredSize];
                    PSP_DEVICE_INTERFACE_DETAIL_DATA_A pDeviceInterfaceDetailData = 
                        (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)buffer;
                    pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);

                    DWORD DeviceInterfaceDetailDataSize = RequiredSize;
                    PDWORD pDeviceInterfaceDetailDataSize = &DeviceInterfaceDetailDataSize;

                    BOOL second_call_result = SetupDiGetDeviceInterfaceDetailA(hDevInfo,
                                                                               pDeviceInterfaceData,
                                                                               pDeviceInterfaceDetailData,
                                                                               DeviceInterfaceDetailDataSize,
                                                                               &RequiredSize,
                                                                               pDeviceInfoData);

                    if (second_call_result == FALSE)
                    {
                        DWORD last_error_number_second_call = GetLastError();
                        CHAR last_error_message_second_call[512];
                        FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0,
                            last_error_number_second_call, 0,
                            last_error_message_second_call,
                            1024, NULL);
    
                    }
                    else
                    {    
                        DWORD dwNumberOfBytesWritten = 0;

                        CHAR szDescription[MAX_PATH];
                        memset(szDescription, 0, MAX_PATH);

                        const GUID* ClassGuid = &(pDeviceInfoData->ClassGuid);
                        SetupDiGetClassDescriptionA(ClassGuid, szDescription, MAX_PATH, &RequiredSize);

                        memset(szDescription, 0, MAX_PATH);
                        SetupDiGetDeviceInstanceIdA(hDevInfo, pDeviceInfoData, szDescription, MAX_PATH, 0);

                        char  szName[64]      = {0};
                        if (SetupDiGetDeviceRegistryProperty(hDevInfo,
                                                    pDeviceInfoData,
                                                    SPDRP_FRIENDLYNAME,
                                                    0L,
                                                    (PBYTE)szName,
                                                    63,
                                                    0))
                        {
                  
                        }
                        else if (SetupDiGetDeviceRegistryProperty(hDevInfo,
                                                                pDeviceInfoData,
                                                                SPDRP_DEVICEDESC,
                                                                0L,
                                                                (PBYTE)szName,
                                                                63,
                                                                0))
                        {
                  
                        };

                        std::string sdrivername = szName;
                        if(sdrivername.find(DRIVER_NAME_USBPRINT) != std::string::npos || sdrivername.find(DRIVER_NAME_USBPRINT_EN) != std::string::npos)
                        {
                            deviceinfo device; 
                            device.sdeviceid = szDescription;
                            device.sdesc = szName;
                            device.sdevicepath =  pDeviceInterfaceDetailData->DevicePath;
                            GetShowNames(device.sdeviceid ,device.sdeviceshow);
                            g_printerdevices.push_back(device);
                        }
                    
                    } // end if second call returned true

                    // now free the buffer
                    delete[] buffer;
                } // end if first call was successful
            } // end if on second call
        } // end iterate through device interfacess
    } // end iterate through device info

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return 0;
}

 

2. 选取一个设备打印

const char initialize_printer_command[] = {ESCAPE_CODE, AT_CODE, NULL_CODE};
const char ESC_WIDTHANDHEGHIT2[] = {0x1c,0x21,12};
int WiterFileInfo(HANDLE handle,const char* sdata)
{

    DWORD dwInitializePrinterNumberOfBytesToWrite = 0;
    DWORD dwInitializePrinterNumberOfBytesWritten = 0;

    dwInitializePrinterNumberOfBytesToWrite = (DWORD)strlen(sdata);

    BOOL ret = WriteFile( handle,
        sdata,
        dwInitializePrinterNumberOfBytesToWrite,
        &(dwInitializePrinterNumberOfBytesWritten),
        NULL);

    return dwInitializePrinterNumberOfBytesWritten;

}


int  USBPrintData(deviceinfo &driver)
{
    HANDLE handle = CreateFileA(driver.sdevicepath.c_str(),
        GENERIC_WRITE | GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        0,
        OPEN_EXISTING,
        0,
        NULL);
    if (handle == INVALID_HANDLE_VALUE)
    {
        CloseHandle(handle);
        return 0;
    }
    else
    {
        int i = 0;
    }

    DWORD dwInitializePrinterNumberOfBytesToWrite = 0;
    DWORD dwInitializePrinterNumberOfBytesWritten = 0;
       //ESC 指令打印
    WiterFileInfo(handle,initialize_printer_command);
       sprintf(write,"%s两倍大小字体\n",ESC_WIDTHANDHEGHIT2);
       WiterFileInfo(handle,write);
       //空白纸走3行
       WiterFileInfo(handle," \n \n \n");
       CloseHandle(handle);
       return 0;
}
      

3: 以上代码只是为了帮助新手成功连接打印机并且打印出字。细节需要自己研究

 

备注

一点ESC指令测试

 

const char ESC_INIT_RWX[] = {0x1B,0x40};            //初始化;              
const char ESC_LINE_TAB[] = {0x0A};                 //换行
const char ESC_LINE_ADD[] = {0x1B,0x21,0x28};       //加粗
//const char ESC_LINE_H2[] = {0x1D,0x21,0x04};      //倍高 垂直( 三位符(倍高度)  1 2 4 8 1-7 倍)
//const char ESC_LINE_W2[] = {0x1D,0x21,0x20};      //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_H1[] = {0x1D,0x21,0x01};        //倍高 垂直( 三位符(倍高度)  1 2 4 8 1-7 倍)
const char ESC_LINE_H2[] = {0x1D,0x21,0x02};        //倍高 垂直( 三位符(倍高度)  1 2 4 8 1-7 倍)
const char ESC_LINE_H3[] = {0x1D,0x21,0x04};        //倍高 垂直( 三位符(倍高度)  1 2 4 8 1-7 倍)

const char ESC_LINE_W1[] = {0x1D,0x21,0x10};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_W2[] = {0x1D,0x21,0x20};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_W3[] = {0x1D,0x21,0x30};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )

const char ESC_LINE_T1[] = {0x1B,0x21,0x02};        //原始高度
const char ESC_LINE_T2[] = {0x1D,0x21,0x11};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_T3[] = {0x1D,0x21,0x22};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_T4[] = {0x1D,0x21,0x34};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )
const char ESC_LINE_T5[] = {0x1D,0x21,0x48};        //倍高 垂直( 三位符(倍高度)  10 20 30 40 宽度 )

 

posted on 2015-11-12 20:17  喜欢做  阅读(3196)  评论(1)    收藏  举报

导航