locked
Cannot connect to a USB printer through CreateFile() and WriteFile(). Please help! RRS feed

  • Discussion générale

  • I have an EPSON receipt impact printer connected to my PC through a USB port. I want my application to send direct output/printer codes to it through calls to WriteFile(). I have two questions:

    1. What should the lpFilename argument of CreateFile() be set to? I can go into Device Manager, look under "Universal Serial Bus controllers," right-click the "EPSON USB Controller for TM/BA/EU Printers," go to Properties, and view properties such as: Hardware Ids, Compatible Ids, Device Class Guid, Driver key, Location information, Device Instance Path, and Container Id. All of these are long strings of hex numbers. I know that one of these should give me the GUID for CreateFile(). Which one is the correct one? Or should the path be something else entirely?

    2. I can retrieve a DevicePath from a call to SetupDiGetDeviceInterfaceDetail, and if I use that in my call to CreateFile() it returns TRUE. However, any attempt to then use WriteFile() results in an error 6 (the handle is invalid), which doesn't make any sense because if the handle was invalid, then CreateFile() would have returned ERROR_INVALID_HANDLE instead of TRUE, right? How can I be certain that I'm writing to the correct USB device?

    Please advise.

    vendredi 13 janvier 2012 22:51

Toutes les réponses

  • what guid are you passing to SetupDiGetClassDevs that is used as the handle to SetupDiGetDeviceInterfaceDetail?  In the end, i don't think the guid matters. IIRC the printing subsystem opens up the printer and you must access the printer through the print spooler APIs, not directly with the hw itself.
    d -- This posting is provided "AS IS" with no warranties, and confers no rights.
    samedi 14 janvier 2012 00:11
  • I am using GUID_DEVINTERFACE_USB_DEVICE. But that's only because after trying about five or six others (such as GUID_DEVINTERFACE_USB_HUB, and GUID_DEVINTERFACE_USB_CONTROLLER, as well as a couple class GUIDs) that was the only one were I got any kind of reasonable results.

    I don't see anything in the printer's programming documentation about how this works, unfortunately; it seems like it shouldn't be that hard once you get control of the right USB port.

    Here's my code so far:

     

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sstream>
    #include <windows.h>
    #include <devguid.h>
    #include <setupapi.h>
    
    // Link with SetupAPI.Lib.
    #pragma comment (lib, "setupapi.lib")
    
    // helpful articles:
    // http://www.codeguru.com/cpp/w-p/system/misc/print.php/c15963
    // http://www.delcom-eng.com/downloads/USBPRGMNL.pdf
    
    const char ESCAPE_CODE = 0x1B;
    const char AT_CODE = 0x40;
    const char NULL_CODE = 0x00;
    
    const char initialize_printer_command[] = {ESCAPE_CODE, AT_CODE, NULL_CODE};
    
    std::string __fastcall int_to_string(int rhs);
    
    void __fastcall LogIt(const std::string& str);
    
    int main()
    {
    // I'm pretty much just Googling "GUID USB printer" and trying anything that shows up.
     
    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 PrinterClassGUID = GUID_DEVCLASS_PRINTER; const GUID USBPrinterGUID = { 0x4d36e979L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } }; const GUID* InterfaceGuid = &GUID_DEVINTERFACE_USB_DEVICE; // The SetupDiGetClassDevs function retrieves a device information set // that contains all devices of a specified class HDEVINFO hDevInfo = SetupDiGetClassDevsA(InterfaceGuid, NULL, // Enumerator NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); if (hDevInfo == INVALID_HANDLE_VALUE) { // Insert error handling here. DWORD last_error = GetLastError(); std::string output = "SetupDiGetClassDevs() returned INVALID_HANDLE_VALUE, error: "; output += int_to_string(last_error); LogIt(output); std::cin.get(); return 1; } LogIt("hDevInfo retrieved successfully."); // Enumerate through all devices in Set. 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++) { // Now get DeviceInterfaceDetailData..."; LogIt("Begin get required buffer size"); 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) { LogIt("ERROR: SetupDiGetDeviceInterfaceDetail returned TRUE on first attempt; supposed to return FALSE"); continue; } else { DWORD first_call_error = GetLastError(); if (first_call_error != ERROR_INSUFFICIENT_BUFFER) { LogIt("ERROR: First call to SetupDiGetDeviceInterfaceDetailA returned invalid error: " + int_to_string(first_call_error)); continue; } else { LogIt("first call returned insufficient buffer. Required size: " + int_to_string(RequiredSize) + " bytes."); LogIt("Begin second call..."); 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); LogIt("ERROR: Second call to SetupDiGetDeviceInterfaceDetailDataA returned FALSE with error: " + int_to_string(last_error_number_second_call) + ", message: '" + last_error_message_second_call + "'"); } else { std::string output = "Success! DevicePath: "; output += pDeviceInterfaceDetailData->DevicePath; LogIt(output); 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); output = "Device Instance ID = '"; output += szDescription; output += "'"; LogIt(output); HANDLE hCOM = CreateFileA(pDeviceInterfaceDetailData->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hCOM == INVALID_HANDLE_VALUE) { CloseHandle(hCOM); // now free the buffer delete[] buffer; continue; } else { LogIt("CreateFileA() was successful!"); } // initialize printer // DWORD dwInitializePrinterNumberOfBytesToWrite = (DWORD)strlen(initialize_printer_command); DWORD dwInitializePrinterNumberOfBytesWritten = 0; LogIt("Now executing initialize_printer_command... "); // Can't get this to work
    BOOL initialize_printer_result = WriteFile( hCOM, initialize_printer_command, dwInitializePrinterNumberOfBytesToWrite, &(dwInitializePrinterNumberOfBytesWritten), NULL); if (initialize_printer_result == 0) { DWORD dwError = GetLastError(); CHAR errmsg[512]; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, errmsg, 1024, NULL); LogIt("ERROR: WriteFile() failed to initialize printer. Error: " + int_to_string(dwError) + " (" + errmsg + " )"); CloseHandle(hCOM); // now free the buffer delete[] buffer; continue; } else {<br/> LogIt("Printer initialized successfully!"); } CloseHandle(hCOM); LogIt("Handle closed"); } // 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 LogIt("calling SetupDiDestroyDeviceInfoList..."); SetupDiDestroyDeviceInfoList(hDevInfo); LogIt("end program"); std::cin.get(); return 0; } std::string __fastcall int_to_string(int rhs) { std::ostringstream stm; stm << rhs; return stm.str(); } void __fastcall LogIt(const std::string& str) { std::string logfilename = "log_usbprinter.txt"; std::ofstream logfile(logfilename.c_str(), std::ios::app); if (!logfile) { std::cout << "ERROR: Could not create log\n"; return; } // output the string to standard output and also add it to a text file std::cout << str.c_str() << std::endl; logfile << str.c_str() << std::endl; logfile.close(); return; }


     



    • Modifié Dwigt samedi 14 janvier 2012 01:48
    samedi 14 janvier 2012 01:45
  •  IIRC the printing subsystem opens up the printer and you must access the printer through the print spooler APIs, not directly with the hw itself.


    Agree with Doron.

    Try WritePrinter API.

    samedi 14 janvier 2012 03:36
  • OK so that has led me to completely scrap all my code and try WritePrinter. but before I can run that I need to call OpenPrinter. One of the parameters of OpenPrinter is PrinterName. I think PrinterName is the description of the printer as it appears in Control Panel. Is that right? If not, how do you find it?
    • Modifié Dwigt samedi 14 janvier 2012 05:10
    samedi 14 janvier 2012 05:10
  • for your education, GUID GUID_DEVINTERFACE_USB_DEVICE is not an interface that you can program against for any usb device. it is enabled for all usb devices as a "homing beacon" to see what usb devices are there, but not to send read/write/IOCTLs to.
    d -- This posting is provided "AS IS" with no warranties, and confers no rights.
    dimanche 15 janvier 2012 00:00
  • Dwigt wrote:
    >
    >OK so that has led me to completely scrap all my code and try WritePrinter.
    >but before I can run that I need to call OpenPrinter. One of the parameters
    >of OpenPrinter is PrinterName. I think PrinterName is the description of
    >the printer as it appears in Control Panel. Is that right? If not, how do
    >you find it?
     
    Googling for "OpenPrinter example" led me to a bunch of solutions, and much
    more quickly than this forums.
    --
    Tim Roberts, timr@probo.com
    Providenza & Boekelheide, Inc.
     

    Tim Roberts, VC++ MVP Providenza & Boekelheide, Inc.
    dimanche 15 janvier 2012 01:11
  • Hey Dwigt,

     

    Any luck with that? I'm in the same situation, with an "Invalid Handle Value" trying to WriteFile.

    Thanks.

    Denys

     

    mardi 24 janvier 2012 22:21