C++ win32 USB打印机开发

    本文地址:http://tongxinmao.com/Article/Detail/id/258

        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 宽度 )

    复制代码

     


    上一篇:打印机语言PostScript和PCL的比较
    下一篇:Delphi打印机编程