Peter’s blog

  • rss
  • Home
  • About
  • Contact

Getting a handle on usbprint.sys

Peter Skarpetis | April 7, 2005 | 12:11 am

So its Thursday morning at work and I decide that since the Mac OS X version of our software can print directly to USB printers bypassing the operating system, its about time we added that functionality to the Linux and Windows versions.

Start on the Linux version

A quick scan through the /usr/src/linux/drivers/usb/devio.c source file reveals all about the usbdevfs file system and the ioctls required. Browse through the USB spec, a few calls to open() and ioctl(), and urb here, an urb there and I’m all done. Piece of cake.

Start on the Windows version

Shudder… Past experiences with Windows and anything to do with low level access to devices has taught me that I am in for the long haul. Each time I try to do something like this it always take 3 - 4 days or excruciating effort and unbearable pain. Oh well, I strap myself to my trusty Aeron chair and away I go.

Now from the MSDN documentation I manage to surmise that as soon as a USB printer is plugged in, the “plug and pray” subsystem loads up the usbprint.sys device driver and passes control over to it. In turn usbprint.sys creates a device node, initialises it and then sets up a device interface so user space programs can access it using the usual device semantics.

Great I think. I’ll just call CreateFile() to open the device and then use WriteFile() to send data to it. Couldn’t be easier. “clickety clack”, the code just flies from my fingers. CreateFile(name….). hmm.. what’s the name of the device. If it was Linux it would be /dev/usblp0 or something like that. Now what is it for Windows. A scan through the MSDN documentation reveals nothing. A search of google produces lots of hits to people asking the same question, but no answers. “Oh, oh this is going to be bad I think”. If there are no answers out there it means it is a closely guarded Microsoft secret and I am going to have to do some deep digging myself.

A more methodical scan of the MSDN docs and Google at least hints to what calls I need to make. In essence you do the following.

  1. Call SetupDiGetClassDevs(interface_guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) to get a list of devices.
  2. Call SetupDiEnumDeviceInterfaces() to get a list of available device interfaces.
  3. Call SetupDiGetDeviceInterfaceDetail() to fetch information for the actual device interface we are going to use.
  4. Use the DevicePath member of the PSP_DEVICE_INTERFACE_DETAIL_DATA structure returned by the SetupDiGetDeviceInterfaceDetail() call as the devicename/filename in the CreateFile() call.
  5. Call WriteFile() repeatedly to send data to the device.
  6. Call CloseHandle() to close the device

So in order to be able to find the name of the device, I need to find the GUID of the interface that usbprint.sys creates when it adds the devicenode to the system. Search… search… search… nothing. Search some more, nothing. Look through the Windows SDK and DDK include files with grep. Still nothing. Oh well up comes trusty old regedit, everything windows does is in the registry, and I start to wade through the myriad of nodes and entries for the GUID. After a few hours of despair I find it. The magic number is 0×28d78fad, 0×5a12, 0×11D1, 0xae, 0×5b, 0×00, 0×00, 0xf8, 0×03, 0xa8, 0xc2. You’d think Microsoft would have included it in one of the .h files (devguid.h or usbprint.h) just like they did the interface GUID for keyboards, mice, hid usb devices, usbcam devices etc. etc. etc.

Oh well at least I can now call open CreateFile and Write to the printer. So here we go:

HANDLE usbHandle = CreateFile(interfacename, GENERIC_WRITE, FILE_SHARE_READ,
                              NULL, OPEN_EXISTING, 0, NULL);
WriteFile(usbhandle, buf, numbytes, &byteswrtten);

The WriteFile call fails and GetLastError() returns 1, ie. the operation is not supported.

More searching, reading, nothing turns up. It keeps failing. I remember that the DDK includes source code for the local portmonitor so I take a look to see how it calls CreateFile for the local port interface. I modify mine to be the same and try again.

HANDLE usbHandle = CreateFile(interfacename, GENERIC_WRITE, FILE_SHARE_READ,
                              NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL |
                              FILE_FLAG_SEQUENTIAL_SCAN, NULL);
WriteFile(usbhandle, buf, numbytes, &byteswrtten);

Success, the printer starts outputting my job. What is different above? Well replacing OPEN_EXISTING with OPEN_ALWAYS seems to have forced the driver to start the device so that the WriteFile interface is available. Previously OPEN_EXISTING would not try and create a file so the device would not start. At least that is what I think.

4 days later and I am all done.

So here is a quick snippet of some of my code to help others out there that might have the same problem. You will need both the windows SDK and DDK installed and configured correctly for this code to compile. You will also need to link your executable with the setupapi library.

Below I have included the code as both an attachment and inline. It is not meant to compile out of the box. It is only there as a guide.

usbprint.c

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

Technorati Tags: usbprint.sys

Categories
Programming
Comments rss
Comments rss
Trackback
Trackback

« Mesmerised babies in Japan Spirited away mural »

78 responses

Nice job. I went through the same process before

R. Rousseau | May 13, 2005 | 5:30 am

Nice job. I went through the same process before finding this recipe.
Microsoft doesn’t want users to “play” with usbprint.sys. This is why the documentation is so hard to find. In the Microsoft Printer Architecture, usbmon.dll is the only one allowed to “talk” to usbprint.sys. You have to play safe because if your printer has a driver installer, the printer spooler via usbmon.dll/usbprint.sys could interact with your application which also uses usbprint.sys. The safest way (I think) if you want to communicate with a USB printer is to make sure there is no driver installer for this printer. If so, usbmon.dll will not open any handles to this printer.

Great Logic ! I have gone through the same problem but

Ganesh | May 28, 2005 | 4:20 pm

Great Logic !
I have gone through the same problem but Jan Axelson’s “USB Complete” helped me a lot.Now I am able to get handle to usbprint.sys and also I can write to Printer(WriteFile returns non zero).
But big problem is printer is not printing my job I am using HP Deskjet 3745 printer.I don’t know what is happening.This is strange situation, WriteFile is successful but printer is not prining the job.

Since the printer is not printing your job, my first

Peter Skarpetis | May 28, 2005 | 10:54 pm

Since the printer is not printing your job, my first guess would be that you are sending it data that is not in the required format so the printer is just ignoring it. When you use usbprint.sys you have to send data that is in the format required by the printer. Usbprint.sys totally bypasses the printer driver, it only provides a transport for data between the computer and the printer, your program will have to do the job of the printer driver.

Good blog Peter. I have some problems compiling your code

Danny | May 31, 2005 | 6:23 pm

Good blog Peter. I have some problems compiling your code in vc++ 6.0. The first to line after include section is getting me a missing semicolon error. I have replace this two line by

static const GUID GUID_DEVINTERFACE_USBPRINT = { 0×28d78fad, 0×5a12, 0×11D1, {0xae, 0×5b, 0×00, 0×00, 0xf8, 0×03, 0xa8, 0xc2} };

but SetupDiEnumDeviceInterfaces don´t retunr any interface.

Your changes look fine to me. In order for the

Peter Skarpetis | June 1, 2005 | 12:41 am

Your changes look fine to me. In order for the call to return some interfaces, you will need to have a usb printer plugged in. Check under computer manangement->system information->usb to see if your printer has an interface instantiated for it.

You can always search through your registry, to see if an interface with that GUID exists on your machine.

Hi Peter, Great article! I am new in this driver

rohit | June 1, 2005 | 10:29 pm

Hi Peter,

Great article! I am new in this driver world want help from u.
I m using Hp printer connected through USB , it has 3 end points.
What my thinking is that To get handle of a particular end point I have to concatenate the device path with the pipe name ( device path I can find by using the method u have described)
Correct me if I am wrong..
In case I am writing to a particular end point & if there is some error ( eg out of paper, paper jam) then how to know the type of error.

That would be the theory, but you would have to

Peter Skarpetis | June 1, 2005 | 10:35 pm

That would be the theory, but you would have to try it. From my experience with Windows, I am a unix guy, anything that seems straightforward never turns out to be. My guess would be that usbprint.sys has grabbed hold of the printer itself and the only way to talk to it is using the device interface as outlined in the post. If you do try it and it works please post a comment here for others to have access to.

Is it possible to set up port mode, control output

Konstantin | June 25, 2005 | 5:48 am

Is it possible to set up port mode, control output lines’ states (nSTROBE, nAUTOFEED, etc.), and read printer status (PE, SELECT, nERROR, …) via usbprint? Does it allow such low-level controlling of the port, or it allows only reading/writing data in SPP/ECP mode?
I want to use USB-to-LPT adapter in EPP mode with my own parallel port device that supports EPP.

USBPrint allows you to send and receive data from the

Peter Skarpetis | June 25, 2005 | 10:26 am

USBPrint allows you to send and receive data from the device using the standard CreateFile, ReadFile and WriteFile interface.

If you want such low level control you will have to write your own device driver or use some other method to send commands to the control pipe of the device. The manufacturer of the device should already be providing tools for doing this.

Hi, thanks for your article. I used this info and

Manuel Chacon | July 11, 2005 | 8:51 am

Hi, thanks for your article. I used this info and now I have a tiny test program in VB. I can send and receive PJL from Lexmark printers.
But, I was unable to do the same with the parallel port. If you have any idea, I will appreciate it. Now, if you think this VB prog. can be useful, let me know and I send it to you

Hi all, I'm new here. Great article. I have the same

Marc | July 11, 2005 | 9:18 pm

Hi all, I’m new here. Great article.
I have the same ‘problem’ as Konstantin. I have an LC-Display which runs well on an old standard parallel port. Now I would like to use it with a USB-to-Parallel cable. the cable uses a prolific PL-2305 chip and Prolific doesn’t provide a driver for XP. I have to control the strope, init, autofeed and selectIn and read back data from the display. Does anyone know, how to realize this? And where can I get a Windows SDK and DDK for VC++6? Microsoft ships only SDK and DDK for .NET, VC6 isn’t supported any more since, ummm, 02/2003 (?).

In order to control the strobe, init autofeed etc. you

Peter Skarpetis | July 11, 2005 | 10:27 pm

In order to control the strobe, init autofeed etc. you will have to somehow send commands to the control pipe of the device. The commands that you send through the control pipe are all very device specific so you would require some information from the manufacturer for that.

Usbprint.sys only allows you to read/write to the device as if it were a file using the CreateFile / ReadFile / WriteFile interface. In order to access the control pipe you would have to write a kernel driver for your specific device.

If you were accessing the device on Linux or Mac OS X you could simply read and write to the control pipe from user mode, but unfortunately Windows does not offer such functionality.

I have worried about that... :-(

Marc | July 12, 2005 | 12:49 am

I have worried about that… :-(

Hi, i need help, i have made some project to output

Afshar | July 19, 2005 | 4:00 am

Hi,

i need help, i have made some project to output signal through parallel,
i had some difficaulty to output directly because microsoft disable it in XP.
so i tried to write small driver send signal to parallel port. and it was fine.

now i need to run this project in my labtop which it has not parallel port, i tried to buy Usb-parallel which it used for printer. but really my code isn’t work because it will send to address 0378 .

i saw you artical and i enjoy it, but really i need some more information. and help from you, to understand how i can solve my problem.

thanx alot for your effort
Afshar

Sorry this post is provided as is. It is somethinng

Peter Skarpetis | July 20, 2005 | 10:36 pm

Sorry this post is provided as is. It is somethinng I discovered after days of intense work and I just wanted to share it with the world.

If you have a usb to parallel box you can use the code in this article to send data to it, but if you wish to do more than that, you will have to get infromation about the chipset used in the adaptor and send commands to it via the control pipe with a kernel driver. This has been covered previously in a comment above and is beyond what this code achieves.

thanx alot for your response. really i want to compile this

Afshar | July 21, 2005 | 3:20 am

thanx alot for your response.

really i want to compile this code but i don’t know how to compile it, can you provide me with complete source code?

and small explanation for compiling this code. coz i think that usb.h is only provided in DDk.

thanx again.

Afshar

if you do not know how to compile this code

Peter Skarpetis | July 21, 2005 | 7:31 am

if you do not know how to compile this code you shouldn’t be trying to do what you are attempting.

the usb include files are part of the ddk which can be found on any miscrosoft msdn distribution. Search through the MSDN documentation to find what you need

I know to compile driver with ddk but it first

Afshar | July 21, 2005 | 1:59 pm

I know to compile driver with ddk but it first time i will compile normal program but it use ddk header files. what i need, is to tell me how to compile non driver with ddk.

do i need to change in SOURCES FILE (TARGETTYPE) to anther thing?

really i don’t need more detail only few help

thanx

I do not use the Microsoft Developer studio, but rather

Peter Skarpetis | July 21, 2005 | 11:05 pm

I do not use the Microsoft Developer studio, but rather I always just handwrite my own Makefiles.

You probably need to add the ddk include and lib directories to your include and library paths on the command line.

I am really surprised that there are programmers out there that cannot perform something as simple as compiling and linking a program. The IDEs that people use these days have a lot to answer for.

I am on you own I am afraid, I am a rather busy man and do not have the time to perform handholding.

dood. thanks. this is exactly what I needed

karen | July 23, 2005 | 5:47 am

dood. thanks. this is exactly what I needed to do before I found out the usb printing support on my XP computer was broken and I spent 3 days trying to figure it out and finally just wiped and reloaded windows. You have saved me at least 3 days of figuring all that stuff out!

Nice job. I'm printing now. I'm currently printing to the

Mike Owens | August 26, 2005 | 2:32 am

Nice job. I’m printing now. I’m currently printing to the first device that gets enumerated. Do you know how I would determine what is connected to the port (in case there is more than 1)?
Thanks

I normally first go through the registry and get a

Peter Skarpetis | August 26, 2005 | 10:04 pm

I normally first go through the registry and get a list of available usb printers including human readable strings. I then use the strings found there to match the required device when searching for the interface to use in CreateFile.

Thanks for your help. One last question if you have

Mike Owens | August 27, 2005 | 12:21 am

Thanks for your help. One last question if you have time. Do you know if the usbprint supports bi-directional communication? When I do ReadFile() I get access denied. The pjlmon sample code supports bidi but I don’t know if it requires a custom usb driver. I apoligize if this is too much. Just ignore if it is.

I'm afraid I have no idea if it does, but

Peter Skarpetis | August 27, 2005 | 12:27 am

I’m afraid I have no idea if it does, but my guess would be that yes it does, but you would need to use the DeviceControl interface with the same ioctlls as the parallel port to achieve this. The MSDN documentation mentions this somewhere. You should also check that you had GENERIC_READ as part of the flags in the CreateFile call. The one I have in my sample code only has GENERIC_WRITE as I never read from the device.

Thank you for your article!

Thank you Peter! | September 5, 2005 | 11:33 am

Thank you for your article!

hi, Peter! I use your code very well,but now i find

Machael | November 29, 2005 | 5:39 pm

hi, Peter!
I use your code very well,but now i find a bug:when the usb is IEEE 1384.4(DOT4), SetupDiGetDeviceRegistryProperty will return FALSE! Do you know why? and how to resolve it?
Thanks!

My code only works with devices that are handled by

Administrator | November 29, 2005 | 8:42 pm

My code only works with devices that are handled by usbprint. If your device is not then it will not be found.

Another thing that might be causing trouble is that your device does not actually have the property you are trying to get. Look through the registry using regedit to see if it does.

Hi Peter! Thanks a lot for sharing this piece of information.

Dmitri | December 9, 2005 | 3:09 pm

Hi Peter!

Thanks a lot for sharing this piece of information. I’m using it to talk to my PIC18F2455 (great little chip btw, lots of fun for AU$10). I wrote printer class firmware for it and I actually managed to get 800Kb/s in both directions. I also tried IOCTL_USBPRINT_GET_LPT_STATUS and IOCTL_USBPRINT_SOFT_RESET codes and they come through just fine, giving me an out-of-band channel to my device.

I have one problem to do with ReadFile() buffer size parameter.
In my setup the PIC is constantly sending packets of the maximum size
as defined in endpoint descriptor (it is always ready to send a packet when PC asks for one to be exact).

First, there seems to be a limit around 3500-3800 bytes on the size of the buffer. If I try to read more in one go, ReadFile() hangs, USB port goes to IDLE state, after killing the process this particular USB port is unusable until reboot.
Second, reading only seems to work if ReadFile() buffer size is an integer multiple of the endpoint buffer size. If not, ReadFile() returns with error 0×1F (”A device attached to the system is not functioning.”).
Howevr it does not happen it the device stops transmitting (i.e. responds with NAK to an IN token) before the buffer is exhausted.
If looks as if ReadFile() keeps asking the device for more packets as long as the device keeps sending then and there is at least one free byte left in the buffer. If the next packet it receives does not fit wholly into what’s left of the buffer it fails with 0×1F. Weird. How and why am I supposed to know about the endpoint buffer size?

Oh, yes, btw, while playing with this stuff I’ve accidentally created a new type of USB devce: “USB instant bluescreen dongle”(c). Just plug it in and Windows XP bluescreens. How? Just implement printer class firmware and politely refuse to provide your 1284 device id. Works 100%. Took me nearly a week’s worth of evenings to figure that out.

I've also come through this lately. Now, using Prolific PL2305

Xander | January 16, 2006 | 11:15 pm

I’ve also come through this lately. Now, using Prolific PL2305 interface, I can do WriteFile and get status of PaperOut (0×20), Select (0×10) and Error (0×08) signals via IOCTL_USBPRINT_GET_LPT_STATUS. I found that Busy and Ack signals are processed internally (data are sent according to their state), but they don’t seem to be readable by a program. As for other control and status signals, I also didn’t find a way to read or write them. The PL2305 datasheet says that other bits (except the mentioned three) of the status register are zeros (confirming the above assumptions).
Unlike Dmitri, I can’t use IOCTL_USBPRINT_SOFT_RESET because it returns with error 1 (function not supported). It looks strange: the datasheet says that such a function exists. Maybe another IOCTL is needed? Note that this signal seems to be the only way to clear buffers, or I’m not right?

Correction to the previous message: Soft Reset is not supported

Xander | January 24, 2006 | 3:17 am

Correction to the previous message: Soft Reset is not supported under Win2000 only. It works well in WinXP. I don’t know about WinME, but I think it works there too. I still wonder if there is another way to reset device (or at least to clear buffers) under Win2000…

I'm still trying to figure out how in the hell

Devin | January 31, 2006 | 3:15 am

I’m still trying to figure out how in the hell to compile this thing…

Never mind! The code works great now. The way I

Devin | January 31, 2006 | 4:40 am

Never mind! The code works great now. The way I got it to compile was by removing all references to DDK headers and compiling it totally using the Visual C++ compiler. No problems yet and I can open a handle and read/write fine. Great job figuring all this stuff out!!

Hi! I am totally new in driver development field. So,

TC | March 15, 2006 | 8:04 pm

Hi! I am totally new in driver development field. So, please bear with me if my questions seem stupid.

1. Can the code function perfectly if I use usb-to-parallel to connect to my printer?

2. I have one parallel device (not a printer), which uses parallel port to work. Now, I want to use usb-to-parallel cable. Can the code used to read/write to my device?

Thanks.

If the USB to parallel device is of class USBPrinter

Administrator | March 15, 2006 | 9:53 pm

If the USB to parallel device is of class USBPrinter and as such is handled by usbprint.sys then the code here will work with it correctly. You can use the computer management tool to check whether your device is being handled by usbprint.sys.

I went to DeviceManager and found that, when I plugged-in

TC | March 16, 2006 | 6:06 pm

I went to DeviceManager and found that, when I plugged-in my usb-to-parallel cable, under ‘Universal Serial Bus controllers’ appeared one ‘USB Printing Support’. I went to its property and the driver files was shown as ‘usbprint.sys’. So, I guess my usb-to-parallel cable is of class USBPrinter.

I am going to try if the piece of code can be used. Thanks!

By the way, how you found the GUID from the registry?

The GUID is the one for usbprint.sys and that is

Peter Skarpetis | March 16, 2006 | 9:22 pm

The GUID is the one for usbprint.sys and that is all handled by the code in this post. Once you’ve enumerated all the devices, you will have to setup your own method for choosing which one you wish to open. I normally pop up a list and let the user choose.

I am using Visual Studio 6.0 with no DDK.

TC | March 17, 2006 | 8:47 pm

I am using Visual Studio 6.0 with no DDK. I changed GUID_DEVINTERFACE_USBPRINT to GUID_DEVCLASS_PRINTER because I have linking error with GUID_DEVINTERFACE_USBPRINT.

Without connecting the cable to my device, I run the code in debug mode. I found that it return 0 in SetupDiEnumDeviceInterfaces(). I used GetLastError() to get the error code, and it is 259 (decimal).

Why is it so? Must I need DDK to make it work?

I do have SDK.

TC | March 17, 2006 | 8:50 pm

I do have SDK.

These lines #define SS_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4,

Peter Skarpetis | March 17, 2006 | 8:52 pm

These lines

#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, 0×28d78fad, 0×5a12, 0×11D1, 0xae,
0×5b, 0×00, 0×00, 0xf8, 0×03, 0xa8, 0xc2);

are used to define GUID_DEVINTERFACE_USBPRINT so you should not be getting a link error as long as you include them in your source code. It has to be in the same file as were you call it from because it is defined as static. If you want it to be visible from other files then change it fro static to something else. Up to you.

Anyway, I am not here to teach people how to program under Windows. I am just providing information that is not available anywhere else.

As far as I've tried, the default Write buffer size

Matthew | March 27, 2006 | 8:45 pm

As far as I’ve tried, the default Write buffer size of usbprint.sys is 4096 bytes.
I wonder if it is possible to extend the size.

I am not sure if you can change it as

Peter Skarpetis | March 27, 2006 | 9:05 pm

I am not sure if you can change it as when writing to a USB device the maximum write size is controlled by the pipe characterstics as published by the USB device itself. Most devices advertise a bulk pipe which is probably what usbprint.sys uses to write to the device. If you use a usbviewer and check out the characteristics of the bulk pipe you should be able to see the maximum allowable write size for your device and then you can possibly use DeviceIOControl to change it.

Did Konstantin or Marc solve there problem of controlling the

RakSac | April 18, 2006 | 3:58 am

Did Konstantin or Marc solve there problem of controlling the Strobe line of the PL2305. I apologize if I ma posting it here but saw some reference of the Prolific PL2305 so wanted to see if there is something already available.

Thanks

Has anyone found a way to link the USBPrint device

Alex | June 20, 2006 | 6:41 pm

Has anyone found a way to link the USBPrint device back to the Windows printer? Basically what I want to do is take the Windows print queue offline before I take over the USBPrint device and start sending PJL commands to the printer - this is to stop anything interferring with my application while it uses the printer. I can take a printer offline OK, I just want a slightly more clever way of doing it than finding out which printer has PRINTER_ATTRIBUTE_LOCAL set and taking that printer offline. In my situation I should never have more than one locally attached printer, but better to do it properly just in case.

Hi Peter this is brilliant i would just like to

Jeremy | July 28, 2006 | 6:59 am

Hi Peter this is brilliant i would just like to know with the createfile() and then deviceiocontrol can i then use a ioctl to do bulk transfers back and forth from my device i have a hp 1300 thanks

No idea. After resolving this problem I have not had

Peter Skarpetis | July 28, 2006 | 12:28 pm

No idea. After resolving this problem I have not had to do any more windows programming as we have our own operating system independent layer that we use in our products. Just check out the windows developer documentation or just try it and see what happens. I would imagine that the call to deviceiocontrol will not work as usbprint.sys is handling the communication with the device and probably does not support that ioctl.

HI, Thanx for this information. But what about using usbmon.dll ie,

Sandeep.S | September 12, 2006 | 4:39 pm

HI, Thanx for this information.
But what about using usbmon.dll ie, Port monitor for usbprintsys. Usbmon maps the spooler or languagemonitor call to kernel mode driver usbprint.sys. I would like to know about the operations of usbmon.dll and the usb specific operations in OpenPort, StartDocPort, EndDocPort, etc.

Thanx in advance

Well now you're pushing your luck. How about you work

Peter Skarpetis | September 12, 2006 | 4:48 pm

Well now you’re pushing your luck. How about you work it out and post it on the Internet for the rest of us to use. It would be really useful.

Hi, I spent a lot of time trying to access

Jordi Vilar | September 21, 2006 | 4:34 am

Hi, I spent a lot of time trying to access the printer in this way (opening the devicepath) It worked ok in winxp/usb2.0, but I found a lot of problems with old computers (win2k/usb1.1) about the block size required in ReadFile and WriteFile, as the system doesn’t provide any buffering. Now I’m trying to use the usbmon.dll but I didn’t succeeded, it always closes my app when calling either StartDocPort or WritePort. Anyone have an idea?
Thanks in advance

HI, Thanx for your helpful artical. I have a question to

Wang Cheng | September 23, 2006 | 1:21 pm

HI, Thanx for your helpful artical.

I have a question to ask you.How can I set the Timeout of the printer USB port for reading and writing operation? I have tried set it by calling
SetCommTimeouts(HANDLE hflie,
PCOMMTIMEOUTS lpCommTimeouts
)
Unluckly, it is a invalid function for the USB device.
Can you give me some advices about how to get and set the USB communication status by the APIs of SDK or DDK.
Waiting for your help!
Thank you very much!

Just use overlapped IO instead of non overlapped and set

Peter Skarpetis | September 24, 2006 | 10:06 am

Just use overlapped IO instead of non overlapped and set the timeout in the call to WaitForSingleObject. This is the same method used for any I/O on Windows.

Let me share with you my findings: About using usbmon.dll: this

Jordi Vilar | September 26, 2006 | 10:39 pm

Let me share with you my findings:
About using usbmon.dll: this dll cannot be used in more than one process at a time, so if the spooler is running you cannot use it.
And about packet sizes, using USB 1.1 all ReadFile calls MUST use a buffer of 64 bytes or a multiple of 64. For USB 2.0, this size is 512. For WriteFile in Windows 2000, maximum block size is 4096.

I'm also interested in the mac version. Could someone please

Jordi Vilar | September 26, 2006 | 10:43 pm

I’m also interested in the mac version. Could someone please enlighten me? Thanks in advance.

Hello Everyone, I have been

Virajitha | September 29, 2006 | 8:05 pm

Hello Everyone,

I have been trying to get the offline\online status of a parallel printer usind Setupdi api functions. I was able to traverse till “LPTENUM\” reg entry and also get the device instance. But when i try to use CM_GET_DEVNODE_STATUS to get the status of the printer, it returns zero whrther printer is connected or not. Lot of search in DDK and Google didnot help me. Can anyone of you tell me if at all we can use setupdi api functions in case of parallel printer.l

Thank you

I'm ignorant of the specific needs discussed here, but if

joe c. | October 25, 2006 | 5:34 am

I’m ignorant of the specific needs discussed here, but if the idea is to send data to a printer, around the printer driver, search MSDN for “RawDataToPrinter”.

The Spooler API explicitly provides this capability: All you need is the printer name.
To summarize the example code provided at msdn.microsoft.com:

OpenPrinter() with printer name,
StartDocPrinter()
StartPagePrinter()
WritePrinter() with pointer and arbitrary size,
EndPagePrinter()
EndDocPrinter()
ClosePrinter().

This works for printers of any port type , network printers, whatever. We use this in several of our in-house utilities.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_93g2.asp

Hope this helps!

I am aware of the OpenPrinter()/ClosePrinter() method of sending raw

Peter Skarpetis | October 25, 2006 | 7:54 am

I am aware of the OpenPrinter()/ClosePrinter() method of sending raw data to an attached printer. The only drawback with this approach is that you need to create a printer first and windows spools the data to disk causing double handling of the data. If your data files are large, this is not a very efficient approach.

Ah, very true. Efficiency?? Intel and DRAM mfgs frown

joe c. | October 26, 2006 | 4:37 am

Ah, very true. Efficiency?? Intel and DRAM mfgs frown upon this statement! There’s nothing that lots more MBytes and MIPS won’t fix… ;-)

Great job with this code, BTW: I am using it to try out some vendor IOCTLs, and it works like a charm. Saved me *lots* of time.
Thanks!

Hey guys I know this might sound stupid but I

Kiran Randhawa | October 27, 2006 | 1:09 am

Hey guys I know this might sound stupid but I am doing a university dissertation… I have a usb to parallel port adapter which uses the usbprint dll file to communicate.

i have no idea at all… basicly all I want to do is output a binary number onto the parallel port through this adapter.. can you guys help me at all I am using visual basic.net

Hi, I need help in order to record printer activities

Muhammad Ali | November 2, 2006 | 6:26 pm

Hi, I need help in order to record printer activities without using spooler . Please help me

Hi, Thanks Peter. I'm working with Device Simulation Framework of the

David Montalvo | November 4, 2006 | 6:26 am

Hi, Thanks Peter.
I’m working with Device Simulation Framework of the WDK. I’m simulating a Printer Device, but I’m creating another BULK OUT endpoint besides standard Protocol 2 Endpoints (1 In, 1 OUT). I modified the bulkusb exmple in the WDK and just added GUID for USBPRINT.sys (The one you name in this article, previusly I was using another GUID [0xa5dcbf10, 0x6530, 0x11d2, 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xe] that enumarates I think all the USB Devices plugged but I have to move through every usb device that is attached, now I only have to move through the USB Printers) and I’m able to write to the Device. The only thingI don’t now how to do, and I think some one in the blog has ask the same, is to select the endpont that i want to write to. Does anyone has some insigth in this matter?
Thanks.

Hi, Manuel Chacon, I saw you've got a VB program

Nico Pyt | November 8, 2006 | 3:20 pm

Hi, Manuel Chacon, I saw you’ve got a VB program that send PJL commands and reads the response… Thats exactly what Im looking for ! ! Please send me the code to npyt AT hotmail.com

thanks

I Peter stupid question im trying to read data from

Jeremy | November 27, 2006 | 9:03 pm

I Peter stupid question im trying to read data from my usb port can i just use readfile if so some how i cant get it to work any ideas i get a handle on the device but some how i cant get it to read but i can write and it does print, please any ideas thanks jeremy

my computer states that I have no operating usb operating.

Joyce A | December 27, 2006 | 6:52 am

my computer states that I have no operating usb operating. Have tried to find help through windows and the printer company and can find no help

hi all i know the code for print a file in

radhika | April 18, 2007 | 9:33 pm

hi all

i know the code for print a file in single pc using serial port now the problem is i need a help for to print a file in network using serial port using java

please any one help for me

thanks

Hi Does the program works for the usb to parallel

frederic | April 21, 2007 | 1:51 am

Hi

Does the program works for the usb to parallel converter for communication PC to PC.

Fred

Dude I have no idea. I provided the code for

Peter Skarpetis | April 21, 2007 | 8:51 am

Dude I have no idea. I provided the code for people to use as is. Why don’t you try it with the usb to parallel converter and post back to this blog for everyone’s benefit.

Peter, I just want to say thank you for working so

John McGlothlan | May 17, 2007 | 7:23 am

Peter,
I just want to say thank you for working so hard and leaving this code available for other developers. It works great.
John

Hi, Manuel Chacon, I saw you’ve got a VB program

osbornl | May 25, 2007 | 9:44 pm

Hi, Manuel Chacon, I saw you’ve got a VB program that send PJL commands and reads the response… Thats exactly what Im looking for ! ! Please send me the code to osbornl@wirelessza.co.za
I have spent a week using Peter’s C code and trying to translate it into vb6

thanks

I believe that it is impossible to talk to the

osbornl | May 25, 2007 | 9:59 pm

I believe that it is impossible to talk to the Parallel port when it has a driver attached to it. Try doing a search for IOOCX. this is a freeware(i believe) parallel port driver

As i am new bee in device and human interactive

sant | June 26, 2007 | 5:14 pm

As i am new bee in device and human interactive world.

its nice to find such people to share their code to the wold for free.

i ahev to write one device driver for USB drive with own protocol. can any one suggest me where to start.

thanks

Could you give me an example of a typical contents

Klaus | July 10, 2007 | 8:55 pm

Could you give me an example of a typical contents of “interfacename” that is passed to CreateFile (line90). (Just to verify my efforts.) Many thanks!

Controlling STROBE, AUTOFEED, INIT, and SELECTIN is not possible using

henni | October 22, 2007 | 8:50 pm

Controlling STROBE, AUTOFEED, INIT, and SELECTIN is not possible using the USB printer class protocol (such signals do not even exist in that specification). Therefore, there is no documented way to do so on the PL-2305 or similar chips. However, querying ERROR, SELECT, and PE is possible using PL-2305, and therefore should be possible using usbprint.sys. ACK and BUSY are not known to USB printer specification, and if you can query these, you are lucky.
See my web site for a PL-2305 replacement that does allow controlling all the lines - even without the hassle of getting the handle to usbprint.sys.

Hi. I have a code in a DLL that can

Ingar Steinsland | October 23, 2007 | 11:07 pm

Hi. I have a code in a DLL that can open a direct communication line to a USB printer. I can give anyone that code for free. But, I have a serious problem: It seems that going in a tight loop calling WriteFile, overruns the printer. After some time it simply stops, and the communication fails. Any ideas?

Hi Peter, Your code serves well as a blueprint and guideline.

Lawrence | November 5, 2007 | 1:25 pm

Hi Peter,

Your code serves well as a blueprint and guideline. At least I gained extremely high confidence seeing so many people having positive result with your code. That gave me the motivation to keep trying with your code (keep trying? allow me to explain later).

To be honest, I am a totally newbie who needs to implement USB printing. I tried #libusb, libusbdotnet, libusb-win32, tons of other references from Google, Microsoft MSDN, other people’s blogs, forums, anything you could imagine in the world of Internet, I tried. However, I didn’t have success with those solution.

Until I ran into your blog during endlessly googling for solution, it gave me some light in the end of tunnel. I really appreciate that. However, it isn’t smooth sailing for me either. I am not too sure how other people in the comments ‘got it work like a charm, magic, ….’ That doesn’t work for me from the first place, I really had hard time to get the code work.

I am totally new to WDK/DDK(in the past). I downloaded WDK for WIndows Vista to my Windows XP [note, WDK for Vista works for XP, according to Microsoft website]. The WDK is a monster download, it is 2.3GB. Setup the right include/lib paths. By the time I thought the code will work like a charm for me, I realize that the code contains some type definition which is unknown to the compiler.

Then I need to find out which include file has the type definition. After that, I discovered that some of the API takes more argument than provided in the code. Being completely ignorant to the API, I need to do some best guess and googling around to temporarily workaround the compilation error. That added into uncertainty if I introduced some bug into the code and made it not working.

Then I ran into runtime issue - the code seems to abort somewhere when it is trying to get some USB information. Then I am not sure if the information is really needed for data writing.

After all those try, try and try, and of course heavily modification to the code, finally it works. And I still don’t know why it will happen, due to different DDK version, compiler version? I don’t know.

There are many comments, those are good suggestions, but I don’t know which is the more workable one for me - some says it works like magic, some says removing the headers, some says compile without DDK, all made up some complicated to follow.

At last, I just want to reiterate - [b]your blog and code are really good starting point for me. I wouldn’t be successful without going through your code, although I did a lot changes to your original code to make it work. [/b]I want to thank you for that. On the other hand, I guess a complete project (with the ready-to-compile-and-build source code and makefile) will make your blog more complete.

I know you are just trying to help. But just that one tiny step from you, will be a big step of help for others struggling to get USB print work. Thanks again for your blog and code.

Hi Peter, I am new to the USB programming. I tried

Yogish | November 21, 2007 | 7:58 pm

Hi Peter,
I am new to the USB programming. I tried the following program with a usb connected mobile phone. But as in the previous discusion the device is not recognised in the device manager. In this situation can u kindly help me how to resolve this.

while(SetupDiEnumDeviceInterfaces(hInfo, 0, (struct _GUID *)&USBIODS_GUID, devicecount, &Interface_Info))
Here the control is not entering inside the while loop.
The PC does not have any drivers for mobile. In this condition , what changes i need to do for establishing the communication. Kindly help as this is a critical issue i am facing.
Thankyou in advance

Hi, I am new to Windows driver programming.I am trying to

Ramgopal Kota | January 7, 2008 | 8:50 pm

Hi,
I am new to Windows driver programming.I am trying to solve a problem we are facing. We have a tool which works with Parallel Port ( LPT1/2/3) to be precise.
Our newer Desktops does not have LPT ports.Hence we thought of using USB to Parallel port cable, but they dont seem to work.
We want to add a ECP port (Dummy One say LPT1) and PIPE the USB Driver so that the data flows out of USB ?
Is it possible ? Is there any soultions for my problem ?

Hello, Does anybody has this code working under .NET ? Is

Danny Lauwers | February 21, 2008 | 9:15 am

Hello,

Does anybody has this code working under .NET ? Is it possible to send some source code to start this USB stuff under .NET ?

I need to get the real-time status of an USB connected HP Laserjet to see if it is Out-Of-Paper. Reading about the GET_PORT_STATUS from the USBPrint specifications this would do the job.

Do you guys think it is possible ?

Tried to compile the original Code under VS2008 (VC++ Project) but I get lot’s of errors. I guess I first need to install the latest SDK’s and DDK’s for the missing include files.

Any help is appriciated !

Thanks
Danny

Does anyone have this code for VB.NET 2005? I can't find

Brandon | May 8, 2008 | 11:12 pm

Does anyone have this code for VB.NET 2005?

I can’t find anything in the registry about GUIDs or the number you found either…

First, thank the blog owner for show us some of

David | May 12, 2008 | 7:25 am

First, thank the blog owner for show us some of his great pieces!

To Dmitri,
Most printer don’t required reverse data transfer, thus readfile can fail to get output from printer.
Most printer comunicated with printer using ieee-1284 device ID ( IOCTL_USBPRINT_GET_1284_ID) data pipe only. Bulk transfer from printer to PC is not nesasary.

To Brandon,
In VB6, I do in this ways.

‘HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{28d78fad-5a12-11d1-ae5b-0000f803a8c2}\##?#USB#Vid_4348&Pid_5584#5&13b4f648&0&1#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

Public Type guid: Data(3) As Long: End Type ‘A GUID is 16 bytes long

Public Sub usbPrintGuid()
‘{28d78fad-5a12-11d1-ae5b-0000f803a8c2}
GUID_DEVINTERFACE_USBPRINT.Data(0) = &H28D78FAD
GUID_DEVINTERFACE_USBPRINT.Data(1) = &H11D15A12
GUID_DEVINTERFACE_USBPRINT.Data(2) = &H5BAE
GUID_DEVINTERFACE_USBPRINT.Data(3) = &HC2A803F8
End Sub

useGuid = GUID_DEVINTERFACE_USBPRINT
PnPHandle& = SetupDiGetClassDevs(useGuid.Data(0), 0, 0, &H12)
If (PnPHandle& = -1) Then ErrorExit (”Could not attach to PnP node”)

Do While SetupDiEnumDeviceInterfaces(PnPHandle&, 0, useGuid.Data(0), HidEntry&, DeviceInterfaceData.cbsize)

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Recent Posts

  • Chatswood Apple store opening soon
  • Manly Dam mountain biking track
  • Scott bike frame falls to pieces
  • Internet kiosk uses Ubuntu
  • udrepper: Memory and Cache Paper
  • Hasselblad’s 39 megapixel H3DII-39MS DSLR brings the multi-shot
  • Switched from Firefox to Opera
  • Mountain Bike Hits 130.7 MPH … on Snow
  • We’ve won!
  • Apple cuts us off

Categories

  • Apple
  • Blogged
  • Cycling
  • Linux
  • Photos
  • Programming
  • Videos

Blogroll

  • My Wiki
  • Serendipity Software
  • Wing

Recent Comments

  • David on Getting a handle on usbprint.sys
  • Brandon on Getting a handle on usbprint.sys
  • aris on Manly Dam mountain biking track
  • Peter Skarpetis on My new bitching mythtv box
  • kc on My new bitching mythtv box
  • Peter Skarpetis on My new bitching mythtv box
  • kc on My new bitching mythtv box
  • Danny Lauwers on Getting a handle on usbprint.sys
  • Ramgopal Kota on Getting a handle on usbprint.sys
  • Yogish on Getting a handle on usbprint.sys

Tags

Apple australia biking mountain sydney
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox