Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7996411
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 4, 20262026-06-04T14:42:12+00:00 2026-06-04T14:42:12+00:00

My goal is to open a printer connected via USB using the CreateFile (and

  • 0

My goal is to open a printer connected via USB using the CreateFile (and then issue some WriteFiles and ReadFiles).

If the printer was an LPT one, I would simply do CreateFile("LPT1:", ...). But for USB printers, there is a special device path that must be passed to CreateFile in order to open that printer.

This device path, as I was able to find, is retrieved via SetupDiGetClassDevs -> SetupDiEnumDeviceInterfaces -> SetupDiGetDeviceInterfaceDetail -> DevicePath member and looks like this:

\\?\usb#vid_0a5f&pid_0027#46a072900549#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

All that is fine, but what I have as the input is the human-readable printer name, as seen in Devices and Printers. The SetupDi* functions don’t seem to use that, they only operate on device instance IDs. So the question is now how to get device instance ID from the printer name one would pass to OpenPrinter.

It’s not difficult to observe that the GUID part of the above is the GUID_DEVINTERFACE_USBPRINT, and \\?\usb is fixed, so the only bit I’m really interested in is vid_0a5f&pid_0027#46a072900549#. This path I can easily look up manually in the printer properties dialog:

Go to Devices and Printers
Right-click the printer
Properties
Switch to Hardware tab
Select the printing device, such as ZDesigner LP2844-Z
Properties
Switch to Details tab
Select ‘Parent’ from the dropdown.

But I have no idea how to do that programmatically provided the only thing given is the printer name as seen in the Device and Printers panel.


P.S. 1: I’m not interested in opening the printer with OpenPrinter and then using WritePrinter / ReadPrinter. That has been done, works fine, but now the goal is different.

P.S. 2: I’ll be OK with a simpler way to convert the readable printer name to something that can be passed to CreateFile.

P.S. 3: This question, to which I have posted an answer, is very related to what I ultimately want to do.

P.S. 4: The other way round is also fine: If it is possible to obtain the readable name from the SP_DEVINFO_DATA structure, that will also be the answer, although a less convenient one.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-04T14:42:13+00:00Added an answer on June 4, 2026 at 2:42 pm

    Below is what I finally have been able to come up with.

    Please confirm that SYSTEM\CurrentControlSet\Control\Print\Printers\{0}\PNPData is a supported path, and not just happens to be there in the current implementation, subject to future changes.

    There’s a little problem with structure alignment, for which I’ve posted a separate question.

    public static class UsbPrinterResolver
    {
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct SP_DEVINFO_DATA
        {
            public uint cbSize;
            public Guid ClassGuid;
            public uint DevInst;
            public IntPtr Reserved;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct SP_DEVICE_INTERFACE_DATA
        {
            public uint cbSize;
            public Guid InterfaceClassGuid;
            public uint Flags;
            public IntPtr Reserved;
        }
    
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        private struct SP_DEVICE_INTERFACE_DETAIL_DATA  // Only used for Marshal.SizeOf. NOT!
        {
            public uint cbSize;
            public char DevicePath;
        }
    
    
        [DllImport("cfgmgr32.dll", CharSet = CharSet.Auto, SetLastError = false, ExactSpelling = true)]
        private static extern uint CM_Get_Parent(out uint pdnDevInst, uint dnDevInst, uint ulFlags);
    
        [DllImport("cfgmgr32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern uint CM_Get_Device_ID(uint dnDevInst, string Buffer, uint BufferLen, uint ulFlags);
    
        [DllImport("cfgmgr32.dll", CharSet = CharSet.Auto, SetLastError = false, ExactSpelling = true)]
        private static extern uint CM_Get_Device_ID_Size(out uint pulLen, uint dnDevInst, uint ulFlags);
    
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetupDiGetClassDevs([In(), MarshalAs(UnmanagedType.LPStruct)] System.Guid ClassGuid, string Enumerator, IntPtr hwndParent, uint Flags);
    
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, uint MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData);
    
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, [In()] ref SP_DEVINFO_DATA DeviceInfoData, [In(), MarshalAs(UnmanagedType.LPStruct)] System.Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
    
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, [In()] ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, uint DeviceInterfaceDetailDataSize, out uint RequiredSize, IntPtr DeviceInfoData);
    
        [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        private static extern int SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
    
        private const uint DIGCF_PRESENT = 0x00000002U;
        private const uint DIGCF_DEVICEINTERFACE = 0x00000010U;
        private const int ERROR_INSUFFICIENT_BUFFER = 122;
        private const uint CR_SUCCESS = 0;
    
        private const int FILE_SHARE_READ = 1;
        private const int FILE_SHARE_WRITE = 2;
        private const uint GENERIC_READ = 0x80000000;
        private const uint GENERIC_WRITE = 0x40000000;
        private const int OPEN_EXISTING = 3;
    
        private static readonly Guid GUID_PRINTER_INSTALL_CLASS = new Guid(0x4d36e979, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
        private static readonly Guid GUID_DEVINTERFACE_USBPRINT = new Guid(0x28d78fad, 0x5a12, 0x11D1, 0xae, 0x5b, 0x00, 0x00, 0xf8, 0x03, 0xa8, 0xc2);
        private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
    
    
        private static string GetPrinterRegistryInstanceID(string PrinterName) {
            if (string.IsNullOrEmpty(PrinterName)) throw new ArgumentNullException("PrinterName");
    
            const string key_template = @"SYSTEM\CurrentControlSet\Control\Print\Printers\{0}\PNPData";
    
            using (var hk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
                                string.Format(key_template, PrinterName),
                                Microsoft.Win32.RegistryKeyPermissionCheck.Default,
                                System.Security.AccessControl.RegistryRights.QueryValues
                            )
                   )
            {
    
                if (hk == null) throw new ArgumentOutOfRangeException("PrinterName", "This printer does not have PnP data.");
    
                return (string)hk.GetValue("DeviceInstanceId");
            }
        }
    
        private static string GetPrinterParentDeviceId(string RegistryInstanceID) {
            if (string.IsNullOrEmpty(RegistryInstanceID)) throw new ArgumentNullException("RegistryInstanceID");
    
            IntPtr hdi = SetupDiGetClassDevs(GUID_PRINTER_INSTALL_CLASS, RegistryInstanceID, IntPtr.Zero, DIGCF_PRESENT);
            if (hdi.Equals(INVALID_HANDLE_VALUE)) throw new System.ComponentModel.Win32Exception();
    
            try
            {
                SP_DEVINFO_DATA printer_data = new SP_DEVINFO_DATA();
                printer_data.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
    
                if (SetupDiEnumDeviceInfo(hdi, 0, ref printer_data) == 0) throw new System.ComponentModel.Win32Exception();   // Only one device in the set
    
                uint cmret = 0;
    
                uint parent_devinst = 0;
                cmret = CM_Get_Parent(out parent_devinst, printer_data.DevInst, 0);
                if (cmret != CR_SUCCESS) throw new Exception(string.Format("Failed to get parent of the device '{0}'. Error code: 0x{1:X8}", RegistryInstanceID, cmret));
    
    
                uint parent_device_id_size = 0;
                cmret = CM_Get_Device_ID_Size(out parent_device_id_size, parent_devinst, 0);
                if (cmret != CR_SUCCESS) throw new Exception(string.Format("Failed to get size of the device ID of the parent of the device '{0}'. Error code: 0x{1:X8}", RegistryInstanceID, cmret));
    
                parent_device_id_size++;  // To include the null character
    
                string parent_device_id = new string('\0', (int)parent_device_id_size);
                cmret = CM_Get_Device_ID(parent_devinst, parent_device_id, parent_device_id_size, 0);
                if (cmret != CR_SUCCESS) throw new Exception(string.Format("Failed to get device ID of the parent of the device '{0}'. Error code: 0x{1:X8}", RegistryInstanceID, cmret));
    
                return parent_device_id;
            }
            finally
            {
                SetupDiDestroyDeviceInfoList(hdi);
            }
        }
    
        private static string GetUSBInterfacePath(string SystemDeviceInstanceID) {
            if (string.IsNullOrEmpty(SystemDeviceInstanceID)) throw new ArgumentNullException("SystemDeviceInstanceID");
    
            IntPtr hdi = SetupDiGetClassDevs(GUID_DEVINTERFACE_USBPRINT, SystemDeviceInstanceID, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
            if (hdi.Equals(INVALID_HANDLE_VALUE)) throw new System.ComponentModel.Win32Exception();
    
            try
            {
                SP_DEVINFO_DATA device_data = new SP_DEVINFO_DATA();
                device_data.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
    
                if (SetupDiEnumDeviceInfo(hdi, 0, ref device_data) == 0) throw new System.ComponentModel.Win32Exception();  // Only one device in the set
    
                SP_DEVICE_INTERFACE_DATA interface_data = new SP_DEVICE_INTERFACE_DATA();
                interface_data.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
    
                if (SetupDiEnumDeviceInterfaces(hdi, ref device_data, GUID_DEVINTERFACE_USBPRINT, 0, ref interface_data) == 0) throw new System.ComponentModel.Win32Exception();   // Only one interface in the set
    
    
                // Get required buffer size
                uint required_size = 0;
                SetupDiGetDeviceInterfaceDetail(hdi, ref interface_data, IntPtr.Zero, 0, out required_size, IntPtr.Zero);
    
                int last_error_code = Marshal.GetLastWin32Error();
                if (last_error_code != ERROR_INSUFFICIENT_BUFFER) throw new System.ComponentModel.Win32Exception(last_error_code);
    
                IntPtr interface_detail_data = Marshal.AllocCoTaskMem((int)required_size);
    
                try
                {
    
                    // FIXME, don't know how to calculate the size.
                    // See https://stackoverflow.com/questions/10728644/properly-declare-sp-device-interface-detail-data-for-pinvoke
    
                    switch (IntPtr.Size)
                    {
                        case 4:
                            Marshal.WriteInt32(interface_detail_data, 4 + Marshal.SystemDefaultCharSize);
                            break;
                        case 8:
                            Marshal.WriteInt32(interface_detail_data, 8);
                            break;
    
                        default:
                            throw new NotSupportedException("Architecture not supported.");
                    }
    
                    if (SetupDiGetDeviceInterfaceDetail(hdi, ref interface_data, interface_detail_data, required_size, out required_size, IntPtr.Zero) == 0) throw new System.ComponentModel.Win32Exception();
    
                    // TODO: When upgrading to .NET 4, replace that with IntPtr.Add
                    return Marshal.PtrToStringAuto(new IntPtr(interface_detail_data.ToInt64() + Marshal.OffsetOf(typeof(SP_DEVICE_INTERFACE_DETAIL_DATA), "DevicePath").ToInt64()));
    
                }
                finally
                {
                    Marshal.FreeCoTaskMem(interface_detail_data);
                }
            }
            finally
            {
                SetupDiDestroyDeviceInfoList(hdi);
            }
        }
    
    
        public static string GetUSBPath(string PrinterName) {
            return GetUSBInterfacePath(GetPrinterParentDeviceId(GetPrinterRegistryInstanceID(PrinterName)));
        }
    
        public static Microsoft.Win32.SafeHandles.SafeFileHandle OpenUSBPrinter(string PrinterName) {
            return new Microsoft.Win32.SafeHandles.SafeFileHandle(CreateFile(GetUSBPath(PrinterName), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero), true);
        }
    
    }
    

    Usage:

    using (var sh = UsbPrinterResolver.OpenUSBPrinter("Zebra Large"))
    {
        using (var f = new System.IO.FileStream(sh, System.IO.FileAccess.ReadWrite))
        {
            // Read from and write to the stream f
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

My goal here is to open temp.php, explode by ### (line terminator), then by
I am using the SharpZipLib open source .net library from www.icsharpcode.net My goal is
Goal Pass images generated by one process efficiently and at very high speed to
Goal : Our application is built using multiple types (e.g. Person, PersonSite(ICollection), Site -
goal : I want to place a text after the submit button using hook_form_alter.
I am using the YUI Progress Bar but I'm having some problems with it.
Goal: To implement a jQuery plugin for my rails app (or write one myself,
Trying to achieve the goal of printing selected page's element ONE-TO-ONE - the exact
I'm doing a little experimentation. The end goal is to open Twitter in a
My goal is to get all images from document, then download all images bigger

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.