Results 1 to 34 of 34

Thread: VB6 and USB

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    VB6 and USB

    Is it possible to properly access a USB device with VB6?

    I'm facing the daunting task of interfacing a VB program with a USB volume control device.

    I've been all over the internet and have found enough information to list USB devices, obtain the full device name needed to use CreateFile to get handles for reading and writing. But I think I have reached either VB's or my limits or maybe both.

    It's a rather simple device, turning the knob left sends a 1 and twisting it to the right and you get a 2. This all works without a problem.

    Now I need to configure the device by sending data to a different End Point and that's got me completely lost.

    Is it even possible to direct output to a different USB End Point with VB?

    Thanks.

  2. #2
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,206

    Re: VB6 and USB

    Vb does not really do anything with USB. It can talk to USB devices via whatever driver the USB device uses provided that driver allows it. For example a USB comm port can be used with MSComm control. A USB keyboard or Mouse just works but there are any number of things that can be connected to a USB port and back when VB6 was released USB was fairly new and had not really taken hold yet.

  3. #3
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: VB6 and USB

    This isn't trivial but it may be possible. It has nothing to do with VB6's age and C# coders struggle just as hard.

    See the sample code in post #5 and beyond of TEMPer Gold USB HID Thermometer Class. The earlier samples require a funky DLL and the later ones do not.

    Long story short:

    Even though this doesn't deal with your specific device it may serve as an example of how a VB6 program can talk fairly directly to USB devices, i.e. without a specific driver.

    I haven't looked at this code in years though, so I can't answer questions about it very quickly. And different devices each require a lot of low-level research and documentation scrounging. This isn't for the faint hearted.

    You will probably need the Windows Driver Kit docs just as a starting point.
    Last edited by dilettante; Jan 20th, 2016 at 11:56 PM.

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Hey dilettante thanks for the info. When I first took a look at the USB specifications I just about fell off my chair. Holly cow, the Apollo Moon Mission seems trivial to this thing! There has to be a bunch of people sitting around some huge conference room table doing nothing more than dreaming up ways to complicate things.

    As I mentioned, I have the basic reading and writing done, but performing any configurations of the device is another story. With my code I can detect the direction of the volume knob, rather straightforward yet I'm guessing 75% if not more of the code is comprised solely of API's, pretty crazy!

    Thanks again for pointing me to sample code.

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    I'm about to throw this USB #@$% out the window!

    Really - could they have made this anymore obscure, confusing and complicated.

    I know so much more about USB devices now then when I started but all it's done for me is created abnormally high blood pressure. The USB device I am working with is a rotary encoder which indicates and reports back to the host the direction it's being turned and when the shaft is being depressed.

    It's a composite device which if I have this correct, is basically two USB devices built into one. You would think that being a composite device, that two device names would show up in the windows device manager, but I have found 4 separate DevicePathNames for this nightmarish piece of hardware.

    I have been able to use CreateFile to get a valid handle to all 4 of the DevicePathNames, but I can only get one of them to respond to I/O requests using WriteFile and ReadFile. The other 3 don't respond to anything I've thrown at it.

    The one DevicePathName that works, is allowing me to read the status of the rotary encoder but this only gets me halfway there. One of the other 3 DevicePathNames is the interface to the other/second composite device that I need in order to configure the device. This is where I am stuck!

    I downloaded a great little monitoring program called DeviceIOView which captures all transactions from the Windows API DeviceIoControl so that you can see what's going on between a host program and a USB device.

    I'm having a little problem with the DeviceIOView utility I downloaded as it displays the Device Names in a format that I don't recognized.

    Currently I'm using a DevicePathName format that looks like this:

    Code:
    "HID\\VID_046D&PID_C318&MI_01&COL02\\7&E04ECA4&0&0001"
    The DeviceIOView utility program is using a Device Name format like this:

    Code:
    "\Device\00000088"
    Does anybody know how to translate between these two Device Name formats? I know it doesn't sound like much but it would be so helpful in testing new approaches. Instead of running every test 3 times, I could focus on a single DevicePathName.

    Thanks

  6. #6
    Hyperactive Member Rattled_Cage's Avatar
    Join Date
    Dec 2005
    Posts
    315

    Re: VB6 and USB

    Quote Originally Posted by stuck-n-past View Post
    I'm about to throw this USB #@$% out the window!
    can you post a link to the usb volume device .....a spec sheet or name of it ?
    does it have install software already ?

    you could make your own like this for about £5 and then send it com port commands down a usb


  7. #7
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: VB6 and USB

    Quote Originally Posted by Rattled_Cage View Post
    can you post a link to the usb volume device .....a spec sheet or name of it ?
    does it have install software already ?
    Yep.

    @OP
    ...without giving us the name(vendor) of your USB-Device, there's only so much one can do from here...

    They usually come with drivers - or in one of the HID-categories - or support virtual COM-ports you
    could connect to over the VB6-MsComm-serial-OCX (per Rs232).

    Here's another (relative) cheap solution, the Controller-Board setting its USB-port
    into HID-mode, so that you will receive normal Key-Strokes and Mouse-Events on your Win-OS.

    https://learn.adafruit.com/pro-trinket-rotary-encoder

    Olaf

  8. #8
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: VB6 and USB

    Another route for HID devices:

    About Raw Input

    There are many user-input devices beside the traditional keyboard and mouse. For example, user input can come from a joystick, a touch screen, a microphone, or other devices that allow great flexibility in user input. These devices are collectively known as Human Interface Devices (HIDs). The raw input API provides a stable and robust way for applications to accept raw input from any HID, including the keyboard and mouse.

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Hello again, here with an update.

    I mentioned above about this being a composite device, having two separate USB devices in one package. Well I have now learned that not only are there two devices, but there are also two separate drivers involved.

    For reading the direction of the encoder, left & right, a HID driver is used which I have working. As for the second device it uses the WinUSB driver which I can't seem to get working.

    Using VB6 I have been able to use CreateFile to get a valid Handle to pass into a call to WinUsb_Initialize which returns successfully, but that's about as far as I can get. The most important WinUsb API calls fall stating that the handle returned from WinUsb_Initialize is invalid.

    These calls work OK:


    Code:
    CreateFile          Return Status: The operation completed successfully
    WinUsb_Initialize   Return Status: Overlapped I/O operation is in progress


    Even though WinUsb_Initialize returns without error, I question the handle it returns as it's an odd type that I don't quite understand. Here is the questionable definition of the m_UsbHandle variable In C++ which I grabbed from some sample code:


    Code:
            typedef HANDLE WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
    
    	HANDLE m_Handle;
    	WINUSB_INTERFACE_HANDLE m_UsbHandle;
    
            m_Handle =  CreateFile("usb device......
            if(m_Handle)
            {
                 m_bResult = WinUsb_Initialize(m_Handle, &m_UsbHandle);
                 if(m_bResult)
                 {
                 printf("OK\n");  
                 }
            }


    For my VB code I defined m_UsbHandle as a Long, and some WinUsb calls appear to work, but then there are others that don't. A big stumbling block here is that I've learned a good number of standard feature supported by WinUsb, were not implemented by the programmer who developed the code for the encoder. From this I don't always know when I have a problem with an API call, or if it's because the features not supported.


    The following routines return successfully, but without any significant information:


    Code:
    WinUsb_GetAssociatedInterface        Return Status: The operation completed successfully
    WinUsb_GetCurrentAlternateSetting    Return Status: No More Data is Available
    WinUsb_QueryInterfaceSettings        Return Status: No More Data is Available
    WinUsb_QueryPipe                     Return Status: No More Data is Available


    The following routines return with errors:


    Code:
    WinUsb_ReadPipe     Return Status: Invalid Handle
    WinUsb_WritePipe    Return Status: Invalid Handle


    While the entire project is in VB6, I have sort of put that aside and put together some C++ code thinking I might get a bit further with there being more example code available. This also has allowed me to remove the doubt surrounding the questionable m_UsbHandle variable definition.

    So I put together a new C++ project, downloading missing files here and there. I was able to get CreateFile working and was ready to test the call to WinUsb_Initialize, when I learned that I don't have the required library needed to link the project! I have WinUsb.h, WinUsb.sys but no WinUsb.lib.

    I'm assuming that WinUsb.lib is the file I need for this thing to link without error but I don't know for sure as I can't find it anywhere! I searched my Disks, CD's and the internet but either it's not out there or I missed it. So I'm guessing it's back to VB.


    As for the Hardware, it appears that I am working with an older/Beta version of a USB-HID Volume Controller V2.0 from morecat_lab. We have exchanged a few emails but there is a bit of a language barrier. The more we talk the more I am wondering if we are working with the same device. I might be looking for a replacement encoder If I can't get this to work.

    Name:  USB Dial.jpg
Views: 5132
Size:  27.5 KB
    Last edited by stuck-n-past; Jan 31st, 2016 at 12:02 AM.

  10. #10

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    So I reload my WDK disk and found my missing file WinUsb.lib which has raised another question. I copied WinUsb.lib to the proper directory but C++ wasn't able to find it. After looking around I realized that my C++ is not pointing to the correct directory.

    I have a multi-boot system and C++ isn't pointing to the correct disk partition. It's looking on drive F:\ when it should be using drive I:\. I've searched for where this might be defined in C++ but no luck. Does anybody know if this is like a re-install sort of fix, or is there just a registry setting that I can change?

    Thanks.


    Oh yea as for the C++ code, I have gotten a little bit further, but now I am working out another problem in trying to initialize the USB device. The newest error I'm fighting is: 'Not enough storage is available to process this command'.

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    After converting the VB code to C++, everything worked!

    The problem appears to be the 'Instance Handle' used by WinUsb_Initialize. VB6 doesn't have a compatible data type, or I at least I can't find one.

    Here is the data type for the Instance Handle in C++

    Code:
     typedef HANDLE WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
    I don't know how to pass a variable to WinUsb_Initialize in VB6 that is compatible with the type shown above, so looks like I'm going to be creating a C++ DLL that I can call from VB6.


    Has anybody else run into problems with Instance Handles like this in VB6?

    Thanks.

  12. #12
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: VB6 and USB

    Device interface handle is long pointer, so one can declare it in VB6 as 'Byval WINUSB_INTERFACE_HANDLE as Long'
    Code:
    Public Declare Function WinUsb_Initialize Lib "winusb.dll" (ByVal deviceHandle As Long, ByRef InterfaceHandle As Long) As Long
    For more information, see this link.
    https://foren.activevb.de/archiv/vb-...Fertiger-Code/
    Last edited by Tech99; Feb 1st, 2016 at 07:45 AM.

  13. #13

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Tech99, that's what I thought and what I tried. In fact it was the first thing I did, using a long variable as the second parameter but it failed every time. I worked on it endlessly without success, that's when I converted my code to C++ and things worked the first time around.

    I know handles are strange animals but they tend to follow a pattern at times. Opening the USB device with CreateFile returns an integer handle in a range of 1500 - 2400. I have printed out the handle in both my VB6 and C++ programs dozens of times. Actually I'm probably closer to printing them out hundreds of times by now, and the handles are always in the same range.

    I have done the same thing with the WinUsb_Initialize instance handle, printing it out every time I do a test run. In the C++ program the value oddly comes up the same each time 1325472. In VB the handle is much larger at a value of 119400256, some 90 times greater then in the C++ version! Right away this sent up a red flag. And it's consistently this large.

    I know it sounds strange to make a decision based on the value of a handle since they are somewhat arbitrary/random, but not only does the handle look wrong, when I try and use it with any of the WinUsb routines an error shows up that the handle is invalid!

    And it's not like the WinUsb_Initialize routine is complicated, two parameters and that's it. And some of the other WinUsb routines are just a simple, sort of hard to mess them up.

    I wanted to force the WinUsb_Initialize to fail just to make sure my code was working trapping and reporting any errors. I pulled out the overlapped flag on the CreateFile routine which is mandatory for WinUsb_Initialize to work. And sure enough the call failed and I caught the error.

    I know this all sounds strange, but converting VB6 to C++ is fairly straight forward, in fact the two programs look very close to one another, almost line for line. If it's not something to do with the definition of this opaque instance handle, then I'm lost as to what it could be.

  14. #14
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: VB6 and USB

    It's hard to guess without code, but it really sound's like a case of a wrong API declares. Somewhere you should be using a Pointer to a handle (ByRef) in the declare and not just a handle (ByVal).

    You definitely want the second parameter ByRef as Long

    Public Declare Function WinUsb_Initialize Lib "winusb" (ByVal DeviceHandle As Long, ByRef InterfaceHandle As Long) As Long
    Last edited by DEXWERX; Feb 1st, 2016 at 12:20 PM.

  15. #15
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: VB6 and USB

    Quote Originally Posted by stuck-n-past View Post
    I have done the same thing with the WinUsb_Initialize instance handle, printing it out every time I do a test run. In the C++ program the value oddly comes up the same each time 1325472. In VB the handle is much larger at a value of 119400256, some 90 times greater then in the C++ version! Right away this sent up a red flag.
    You can't base success/failure by evaluating handle value. Absolutely no, even if/when handle value follow/do not follow certain pattern/value range between languages.

    Use the declaration listed in above and examine function return value.

    Code:
    success = WinUsb_Initialize (myDevInfo.deviceHandle, MyDevInfo.winUsbHandle)
                    
                    If success Then...

  16. #16

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    I have a check after all the API calls, and the declaration matches what you have shown. The call to WinUsb_Initialize is successful, the very next line of code after the 'if success' is a call to WinUsb_QueryInterfaceSettings, which says the instance handle is invalid.

    These few lines of VB6 code are almost identical to my C++ version, however the C++ version works. The only real difference is the deceleration of the instance handle variable.

  17. #17
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: VB6 and USB

    Quote Originally Posted by stuck-n-past View Post
    I have a check after all the API calls, and the declaration matches what you have shown. The call to WinUsb_Initialize is successful, the very next line of code after the 'if success' is a call to WinUsb_QueryInterfaceSettings, which says the instance handle is invalid.
    It seems that you didn't call IIDFromString and/or SetupDiGetClassDevs function, before init.

  18. #18

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Actually that's close to one of the first routines I call.

    I call HidD_GetHidGuid to start things off and then I call SetupDiGetClassDevs.

    I have been going over both the VB6 and C++ code trying to see where there might be any differences, but I can't find anything. So with things working so well in C++ I think it's time to build a DLL wrapper that I can call from the VB project. Sometimes you just have to go with what works.

    It won't take too much time to code the wrapper, and perhaps once the project is done, I can revisit the issue searching for a solution to the problem.


    Thanks for all of the help.

  19. #19
    Junior Member
    Join Date
    Jun 2015
    Posts
    23

    Re: VB6 and USB

    I've spent a fairly tremendous amount of time working with USB in VB6, specifically with USB printers.

    Here's a snippet that has to do with generating a list of all the USB printers currently on the system using only built-in system APIs. It may be missing a few declares since its a snippet of a much much larger tool, but it should give the idea.

    The output of the function is a 2d array containing a magic path you can use with createfile, readfile and writefile in the 0 element, and the driver key (aka software key) in the 1 element. The output would be something like:

    \\?\usb#vid_0a5f&pid_00bd#xxqlj124500138#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

    for the first string (which has the vid, the pid, the serial number and the port's GUID), and

    {36fc9e60-c465-11cf-8056-444553540000}\0152

    for the second.

    This particular code also does other things, like determine which USB stack is responsible for managing the printer device (in windows you can have more than one USB stack installed), and also who is the parent device (the hub) of the printer (though some of that is commented out).

    If it would be useful I could boil this down into an example but it seems you are already pretty close to a working solution.

    Code:
    Private Const DIGCF_PRESENT = &H2
    Private Const DIGCF_DEVICEINTERFACE = &H10
    Const DIGCF_ALLCLASSES As Long = &H4
    Const OVERLAPPED_IO_PENDING = 997
    Const STATUS_PENDING = 259
    
    Private Type OVERLAPPED
        lpInternal As Long
        lpInternalHigh As Long
        offset As Long
        OffsetHigh As Long
        hEvent As Long
    End Type
    
    Private Type SP_DEVICE_INTERFACE_DETAIL_DATA
        cbSize As Long
        DataPath(256) As Byte
    End Type
    
    Private Type SP_DEVICE_INTERFACE_DATA
        cbSize As Long
        InterfaceClassGuid As GUID
        Flags As Long
        ReservedPtr As Long
    End Type
    
    
    Private Type SP_DEVINFO_DATA
      cbSize As Long
      InterfaceClassGuid As GUID
      hDevInst As Long
      ReservedPtr As Long
    End Type
    
    Private Declare Function SetupDiGetClassDevs Lib "setupapi.dll" Alias "SetupDiGetClassDevsA" (HidGuid As GUID, ByVal EnumPtr As Long, ByVal hwndParent As Long, ByVal Flags As Long) As Long
    Private Declare Function SetupDiDestroyDeviceInfoList Lib "setupapi.dll" (ByVal DeviceInfoSet As Long) As Boolean
    Private Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" (ByVal Handle As Long, ByVal InfoPtr As Long, HidGuid As GUID, ByVal MemberIndex As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Boolean
    Private Declare Function SetupDiEnumDeviceInterfacesWithInfoPtr Lib "setupapi.dll" Alias "SetupDiEnumDeviceInterfaces" (ByVal Handle As Long, ByRef InfoPtr As SP_DEVINFO_DATA, HidGuid As GUID, ByVal MemberIndex As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Boolean
    Private Declare Function SetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailA" (ByVal Handle As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, FunctionClassDeviceData As SP_DEVICE_INTERFACE_DETAIL_DATA, ByVal DetailLength As Long, lpReturnedLength As Long, deviceInfoData As SP_DEVINFO_DATA) As Boolean
    Private Declare Function SetupDiOpenDeviceInfo Lib "setupapi.dll" Alias "SetupDiOpenDeviceInfoA" (ByVal DeviceInfoSet As Long, ByRef DeviceInstanceId As Any, ByVal hwndParent As Long, ByVal OpenFlags As Long, ByRef deviceInfoData As SP_DEVINFO_DATA) As Long
    
    Private Declare Function CM_Get_Device_ID_Size Lib "cfgmgr32.dll" (ByRef pulLen As Long, ByVal dnDevInst As Long, ByVal ulFlags As Long) As Long
    Private Declare Function CM_Get_Device_ID Lib "cfgmgr32.dll" Alias "CM_Get_Device_IDA" (ByVal lDnDevInst As Long, pBuffer As Any, lLength As Long, ByVal lFlags As Long) As Long
    Private Declare Function CM_Get_Parent Lib "cfgmgr32.dll" (lDnDevInst As Long, ByVal lDnDevInst As Long, ByVal lFlags As Long) As Long
    Private Declare Function CM_Get_Sibling Lib "cfgmgr32.dll" (lDnDevInst As Long, ByVal lDnDevInst As Long, ByVal lFlags As Long) As Long
    
    Private PrinterGUID As GUID                         'Used for enumerating USB Devices
    Private USBStackGUID As GUID                        'Used for enumerating USB Devices
    
    
    Function Init()
        PrinterGUID.DataL = &H28D78FAD
        PrinterGUID.data1 = &H5A12
        PrinterGUID.data2 = &H11D1
        PrinterGUID.DataB(0) = &HAE
        PrinterGUID.DataB(1) = &H5B
        PrinterGUID.DataB(2) = 0
        PrinterGUID.DataB(3) = 0
        PrinterGUID.DataB(4) = &HF8
        PrinterGUID.DataB(5) = 3
        PrinterGUID.DataB(6) = &HA8
        PrinterGUID.DataB(7) = &HC2
            
        USBStackGUID.DataL = &HF18A0E88
        USBStackGUID.data1 = &HC30C
        USBStackGUID.data2 = &H11D0
        USBStackGUID.DataB(0) = &H88
        USBStackGUID.DataB(1) = &H15
        USBStackGUID.DataB(2) = 0
        USBStackGUID.DataB(3) = &HA0
        USBStackGUID.DataB(4) = &HC9
        USBStackGUID.DataB(5) = &H6
        USBStackGUID.DataB(6) = &HBE
        USBStackGUID.DataB(7) = &HD8
    End Function
    
    Private Function CreateListOfUSBPrinters(Optional lngErrorResult As Long = 0) As String()
        
        Dim HDEVINFO_USBPrinterClassDevs As Long
        Dim HDEVINFO_USBClassDevs As Long
        Dim PSP_DEVINFO_DATA_NULL As Long
        Dim PDEVINST_ParentDevInst As Long
        
        Dim typChildDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
        Dim typChildDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim typChildDevInfoData As SP_DEVINFO_DATA
        Dim strChildPath As String
        
        Dim typParentDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
        'Dim typParentDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim typParentDevInfoData As SP_DEVINFO_DATA
        Dim bytParentDeviceInstanceID() As Byte
        'Dim strParentPath As String
        
        Dim strHoldingArray() As String
    
        Dim lngResultingSize As Long
        
        Dim DP_SIZE As Long
        
        If Globals.InIde Then On Error GoTo 0 Else On Error GoTo LocalErrorHandler
        
        DP_SIZE = UBound(typChildDeviceInterfaceDetailData.DataPath)
        
        ReDim bytParentDeviceInstanceID(DP_SIZE) As Byte
        
        Const MIN_SIZE = 5
        Const CR_SUCCESS = 0
        Const ERROR_NO_MORE_ITEMS = 259
    
        Dim lngDeviceInterfaceIndex As Long
        Dim lngDeviceInterfaceCount As Long
            
        ' Fill in initial sizes for structures
        typChildDeviceInterfaceData.cbSize = Len(typChildDeviceInterfaceData)
        typChildDevInfoData.cbSize = Len(typChildDevInfoData)
        
        ' Fill in initial sizes for structures
        typParentDeviceInterfaceData.cbSize = Len(typParentDeviceInterfaceData)
        typParentDevInfoData.cbSize = Len(typParentDevInfoData)
    
        lngErrorResult = 0
    
        Do
            
            ' Create initial device information lists - one for USB Printers, one for generic USB devices
            HDEVINFO_USBPrinterClassDevs = SetupDiGetClassDevs(PrinterGUID, 0, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
            HDEVINFO_USBClassDevs = SetupDiGetClassDevs(USBStackGUID, 0, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
            
            ' If either is invalid, give up
            If HDEVINFO_USBPrinterClassDevs = INVALID_HANDLE_VALUE Then Exit Do
            If HDEVINFO_USBClassDevs = INVALID_HANDLE_VALUE Then Exit Do
            
            ' Count how many USB printer devices we have
            Do While SetupDiEnumDeviceInterfaces(HDEVINFO_USBPrinterClassDevs, PSP_DEVINFO_DATA_NULL, PrinterGUID, lngDeviceInterfaceCount, typChildDeviceInterfaceData)
                lngDeviceInterfaceCount = lngDeviceInterfaceCount + 1
            Loop
        
            ' If we have zero, or we had an error, give up
            If Err.LastDllError <> ERROR_NO_MORE_ITEMS Or lngDeviceInterfaceCount = 0 Then Exit Do
            
            ReDim strHoldingArray(0 To lngDeviceInterfaceCount - 1, 0 To 1) As String
            
            ' Interate over each device
            Do While SetupDiEnumDeviceInterfaces(HDEVINFO_USBPrinterClassDevs, PSP_DEVINFO_DATA_NULL, PrinterGUID, lngDeviceInterfaceIndex, typChildDeviceInterfaceData)
                
                ' You must setup this structure to the fixed size, not the total size. The fixed size is 5 bytes.
                typChildDeviceInterfaceDetailData.cbSize = MIN_SIZE
                ZeroMemory typChildDeviceInterfaceDetailData.DataPath(0), DP_SIZE
                
                ' Get the child's interface detail (path)
                If False = SetupDiGetDeviceInterfaceDetail(HDEVINFO_USBPrinterClassDevs, typChildDeviceInterfaceData, typChildDeviceInterfaceDetailData, DP_SIZE, lngResultingSize, typChildDevInfoData) Then
                    Exit Do
                End If
                
                ' Generate the Child's path
                strChildPath = StrConv(typChildDeviceInterfaceDetailData.DataPath, vbUnicode)
                strChildPath = Left(strChildPath, lngResultingSize - MIN_SIZE)
                
                Dim varResult As Variant
                Dim typSP As typSP_DEVINFO_DATA
                
                CopyMemory typSP.lSize, typChildDevInfoData.cbSize, typChildDevInfoData.cbSize
                
                If SetupDiGetDeviceRegistryProperty(HDEVINFO_USBPrinterClassDevs, typSP, SPDRP_DRIVER, varResult) = False Then
                    Exit Do
                End If
                
                
                ' Get the parent's Device Instance Handle
                If CR_SUCCESS <> CM_Get_Parent(PDEVINST_ParentDevInst, typChildDevInfoData.hDevInst, 0) Then
                    Exit Do
                End If
                           
                ' Clear the Parent's device ID
                'ZeroMemory bytParentDeviceInstanceID(0), DP_SIZE
                'lngResultingSize = 0
                                        
                ' Get the Parentn's Device Instance ID string
                'If CR_SUCCESS <> CM_Get_Device_ID(PDEVINST_ParentDevInst, bytParentDeviceInstanceID(0), DP_SIZE, 0) Then
                '    Exit Do
                'End If
                
                ' From that string get a Device Info Data structure, and add it to the USB Class device information list
                ' This will also generate us our parent's device information data
                'If False = SetupDiOpenDeviceInfo(HDEVINFO_USBClassDevs, bytParentDeviceInstanceID(0), 0, 0, typParentDevInfoData) Then
                '    Exit Do
                'End If
        
                ' Enumerate the device we just added to get the parent's device interface data
                'If False = SetupDiEnumDeviceInterfacesWithInfoPtr(HDEVINFO_USBClassDevs, typParentDevInfoData, USBStackGUID, 0, typParentDeviceInterfaceData) Then
                '    Exit Do
                'End If
        
                ' Clear the structure
                'typParentDeviceInterfaceDetailData.cbSize = MIN_SIZE
                'ZeroMemory typParentDeviceInterfaceDetailData.DataPath(0), DP_SIZE
        
                ' Get the parent's interface detail (path)
                'If False = SetupDiGetDeviceInterfaceDetail(HDEVINFO_USBClassDevs, typParentDeviceInterfaceData, typParentDeviceInterfaceDetailData, DP_SIZE, lngResultingSize, typParentDevInfoData) Then
                '    Exit Do
                'End If
        
                ' Generate the Parent's path
                'strParentPath = StrConv(typParentDeviceInterfaceDetailData.DataPath, vbUnicode)
                'strParentPath = Left(strParentPath, lngResultingSize - MIN_SIZE)
        
                strHoldingArray(lngDeviceInterfaceIndex, 0) = strChildPath
                strHoldingArray(lngDeviceInterfaceIndex, 1) = varResult
                
                lngDeviceInterfaceIndex = lngDeviceInterfaceIndex + 1
                
            Loop
        
            Exit Do
        Loop
    
        lngErrorResult = Err.LastDllError
    
        SetupDiDestroyDeviceInfoList HDEVINFO_USBClassDevs
        SetupDiDestroyDeviceInfoList HDEVINFO_USBPrinterClassDevs
        
        CreateListOfUSBPrinters = strHoldingArray
        
    Exit Function
    
    LocalErrorHandler:
      
      If GlobalError("clsCommuncation:CreateListOfUSBPrinters", Err.Number, Err.Source, Err.Description) = 1 Then Resume Next
            
    End Function

  20. #20
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: VB6 and USB

    @stuck-n-past Let me see if I can debug what you got here... oh wait. no one can do anything but speculate.

  21. #21

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Hey interactii, thanks for your post. This project is my first attempt at working with USB devices and it truly does seem more complicated then it needs to be, dilettante was quite accurate in his remark


    This isn't trivial but it may be possible. It has nothing to do with VB6's age and C# coders struggle just as hard.


    At the start of the project I assumed I would be working with a single interface, specifically one supporting HID devices. Going in that direction my largest hurdle was in how to specify the Endpoint I wanted to use. Reading through USB documentation, I came across a method used to select the desired Endpoint by tacking the Pipe ID to the end of the device name. I never could get it to work and started to think it might be outdated information. That was until I read your post and saw something that caught my eye.


    {36fc9e60-c465-11cf-8056-444553540000}\0152


    In the above quote, is the "\0152" specifying an Endpoint? If so, I might go back and take another look at using the HID routines to access the device.

    I've completed the C++ DLL which I now use in the VB project, so everything is pretty much done in regards to the USB interface, but the simpler you can make things, the better success there tends to be.

  22. #22

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Something got me to thinking about this USB project. Coding in VB I made use of the WinUsb.DLL to access the appropriate routines. I then coded the same project over in C++ but this time I made use of the WinUsb.lib, calling the routines directly or so I'm guessing. Does that mean that the WinUsb Library was also written in C++?

  23. #23
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: VB6 and USB

    .lib files are also created for VB6 ActiveX DLLs. It just lets the linker know how to call the dll. I'm guessing it was written in C++, but the lib file has nothing to do with it.

  24. #24

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    When my VB program calls a routine like WinUsb_Initialize does it use WinUsb.DLL alone, or does it also use WinUsb.lib?

  25. #25
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: VB6 and USB

    Quote Originally Posted by stuck-n-past View Post
    When my VB program calls a routine like WinUsb_Initialize does it use WinUsb.DLL alone, or does it also use WinUsb.lib?
    The information in the .Lib is compiled into your executable. So... it depends what you mean. You'll never need the .lib again, after your program is compiled. the .lib is IN your program It's no longer a dependancy.

    The WinUSB.DLL is (sort of, you definitely don't want to redistribute that dependancy)

  26. #26

    Re: VB6 and USB

    Well actually i always use USB to VB when connecting to my microcontroller, i have a source code library from Jan Axelson from the book "USB Complete 4th edition"
    http://janaxelson.com/usbc.htm

    here is the simple code that covers the basic usb communication, coded in PURE VB with only Windows API. Hope it helps!
    Attached Files Attached Files
    Last edited by si_the_geek; Feb 10th, 2016 at 06:44 AM. Reason: removed executable

  27. #27
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: VB6 and USB

    I have removed the executable file your attachment to protect our members, because we have no way of knowing what an executable file actually does - which could include something malicious, such as if there is a virus on your computer.

  28. #28

    Re: VB6 and USB

    Oh, thankyou!

    I just happened to compress the entire folder, not realizing that the compiled exe was there.

  29. #29

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Sorry for taking so long to respond.

    One of the reasons I was asking about the libraries is that in my C++ program there is an option to use shared DLL's or static libraries. When I have the option set to use DLL's the program doesn't run properly. Changing the option to use static libraries and everything works. This made me wonder if I have a bad DLL file which is not only causing a problem with the C++ program, but perhaps it's the gremlin I've been chasing in my VB program.

    By using the static library option in C++, could I be bypassing a corrupt file? From what everybody is saying, there is no reason why WinUsb_Initialize should be failing in VB but working just fine in C++.

  30. #30
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: VB6 and USB

    static linking only applies to runtime files, not OS DLLs. If you don't static link, you have to have the redistributable runtime DLLs installed for whatever version of MSVC you are using... although that should be installed when you installed VC??

  31. #31

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    Oh well, so much for the theory of having a bad DLL file on the VB side of things. Having the guts of the project done in C++, the VB WinUsb_Initialize Mystery might just go unsolved.

    astralist, thanks for the code example. I have a question about one of the SetupDi calls made using VarPtr and a byte array. Couldn't the same thing be accomplished by passing the parameter DetailDataBuffer by reference to have it's address placed on the call stack?


    Code:
                
                Result = SetupDiGetDeviceInterfaceDetail _
                   (DeviceInfoSet, _
                   MyDeviceInterfaceData, _
                   VarPtr(DetailDataBuffer(0)), _
                   DetailData, _
                   Needed, _
                   0)

    Thanks.

  32. #32

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    happy to say that I'm done with the C++ part of the code and back to VB. With all of the USB I/O stuff done I have been cleaning up working on the user interface when I came across some confusion with Device Names.

    Using the SetupDi API routines to retrieve the DevicePathName to hand off to CreateFile, I've found that it doesn't quite work the way the documentation says is should. The problem is with the GUID tacked onto the end of the USB device name and whether it's a Class or Interface GUID.

    From what I can tell, CreateFile wants a Class GUID on the end of the device name, but the SetupDi routines, specifically, SetupDiGetDeviceInterfaceDetail, returns an Interface GUID. Using this Inteface GUID from the SP_DEVICE_INTERFACE_DETAIL_DATA structure fails when used with CreateFile.

    This is only true when using a 'wild card' search with SetupDiGetClassDevs to return all devices. If passing a Class GUID to SetupDiGetClassDevs, then that's what will be returned in the DevicePathName.

    So is there anyway to use an interface GUID to find the class GUID it belongs to?

    Thanks.
    Last edited by stuck-n-past; Feb 13th, 2016 at 05:54 PM.

  33. #33

    Thread Starter
    Fanatic Member
    Join Date
    Nov 2014
    Posts
    553

    Re: VB6 and USB

    I surrender! From time to time I have gone gone back to work on the USB code. For standard devices you can use known GUID's such as {4d1e55b2-f16f-11cf-88cb-001111000030} for a HID interface, for non standard devices I have only found the proper GUID hiding in the associated ini file. I've tried using so many different API calls, DeviceIoControl, SetupDi, CM_, CreateFile... and a ton of others, I've ended up with enough test code to have a VB6 version of USBView. Even with all that code I Still cant find a better way to locate the proper GUID other then using the ini file. Either the ini file is the way to go or a better way doesn't exist. Then again there is a good chance I've just been barking up the wrong tree.

  34. #34
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,169

    Re: VB6 and USB

    Quote Originally Posted by interactii View Post
    I've spent a fairly tremendous amount of time working with USB in VB6, specifically with USB printers.

    Here's a snippet that has to do with generating a list of all the USB printers currently on the system using only built-in system APIs. It may be missing a few declares since its a snippet of a much much larger tool, but it should give the idea.

    The output of the function is a 2d array containing a magic path you can use with createfile, readfile and writefile in the 0 element, and the driver key (aka software key) in the 1 element. The output would be something like:

    \\?\usb#vid_0a5f&pid_00bd#xxqlj124500138#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

    for the first string (which has the vid, the pid, the serial number and the port's GUID), and

    {36fc9e60-c465-11cf-8056-444553540000}\0152

    for the second.

    This particular code also does other things, like determine which USB stack is responsible for managing the printer device (in windows you can have more than one USB stack installed), and also who is the parent device (the hub) of the printer (though some of that is commented out).

    If it would be useful I could boil this down into an example but it seems you are already pretty close to a working solution.

    Code:
    Private Const DIGCF_PRESENT = &H2
    Private Const DIGCF_DEVICEINTERFACE = &H10
    Const DIGCF_ALLCLASSES As Long = &H4
    Const OVERLAPPED_IO_PENDING = 997
    Const STATUS_PENDING = 259
    
    Private Type OVERLAPPED
        lpInternal As Long
        lpInternalHigh As Long
        offset As Long
        OffsetHigh As Long
        hEvent As Long
    End Type
    
    Private Type SP_DEVICE_INTERFACE_DETAIL_DATA
        cbSize As Long
        DataPath(256) As Byte
    End Type
    
    Private Type SP_DEVICE_INTERFACE_DATA
        cbSize As Long
        InterfaceClassGuid As GUID
        Flags As Long
        ReservedPtr As Long
    End Type
    
    
    Private Type SP_DEVINFO_DATA
      cbSize As Long
      InterfaceClassGuid As GUID
      hDevInst As Long
      ReservedPtr As Long
    End Type
    
    Private Declare Function SetupDiGetClassDevs Lib "setupapi.dll" Alias "SetupDiGetClassDevsA" (HidGuid As GUID, ByVal EnumPtr As Long, ByVal hwndParent As Long, ByVal Flags As Long) As Long
    Private Declare Function SetupDiDestroyDeviceInfoList Lib "setupapi.dll" (ByVal DeviceInfoSet As Long) As Boolean
    Private Declare Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" (ByVal Handle As Long, ByVal InfoPtr As Long, HidGuid As GUID, ByVal MemberIndex As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Boolean
    Private Declare Function SetupDiEnumDeviceInterfacesWithInfoPtr Lib "setupapi.dll" Alias "SetupDiEnumDeviceInterfaces" (ByVal Handle As Long, ByRef InfoPtr As SP_DEVINFO_DATA, HidGuid As GUID, ByVal MemberIndex As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Boolean
    Private Declare Function SetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailA" (ByVal Handle As Long, DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, FunctionClassDeviceData As SP_DEVICE_INTERFACE_DETAIL_DATA, ByVal DetailLength As Long, lpReturnedLength As Long, deviceInfoData As SP_DEVINFO_DATA) As Boolean
    Private Declare Function SetupDiOpenDeviceInfo Lib "setupapi.dll" Alias "SetupDiOpenDeviceInfoA" (ByVal DeviceInfoSet As Long, ByRef DeviceInstanceId As Any, ByVal hwndParent As Long, ByVal OpenFlags As Long, ByRef deviceInfoData As SP_DEVINFO_DATA) As Long
    
    Private Declare Function CM_Get_Device_ID_Size Lib "cfgmgr32.dll" (ByRef pulLen As Long, ByVal dnDevInst As Long, ByVal ulFlags As Long) As Long
    Private Declare Function CM_Get_Device_ID Lib "cfgmgr32.dll" Alias "CM_Get_Device_IDA" (ByVal lDnDevInst As Long, pBuffer As Any, lLength As Long, ByVal lFlags As Long) As Long
    Private Declare Function CM_Get_Parent Lib "cfgmgr32.dll" (lDnDevInst As Long, ByVal lDnDevInst As Long, ByVal lFlags As Long) As Long
    Private Declare Function CM_Get_Sibling Lib "cfgmgr32.dll" (lDnDevInst As Long, ByVal lDnDevInst As Long, ByVal lFlags As Long) As Long
    
    Private PrinterGUID As GUID                         'Used for enumerating USB Devices
    Private USBStackGUID As GUID                        'Used for enumerating USB Devices
    
    
    Function Init()
        PrinterGUID.DataL = &H28D78FAD
        PrinterGUID.data1 = &H5A12
        PrinterGUID.data2 = &H11D1
        PrinterGUID.DataB(0) = &HAE
        PrinterGUID.DataB(1) = &H5B
        PrinterGUID.DataB(2) = 0
        PrinterGUID.DataB(3) = 0
        PrinterGUID.DataB(4) = &HF8
        PrinterGUID.DataB(5) = 3
        PrinterGUID.DataB(6) = &HA8
        PrinterGUID.DataB(7) = &HC2
            
        USBStackGUID.DataL = &HF18A0E88
        USBStackGUID.data1 = &HC30C
        USBStackGUID.data2 = &H11D0
        USBStackGUID.DataB(0) = &H88
        USBStackGUID.DataB(1) = &H15
        USBStackGUID.DataB(2) = 0
        USBStackGUID.DataB(3) = &HA0
        USBStackGUID.DataB(4) = &HC9
        USBStackGUID.DataB(5) = &H6
        USBStackGUID.DataB(6) = &HBE
        USBStackGUID.DataB(7) = &HD8
    End Function
    
    Private Function CreateListOfUSBPrinters(Optional lngErrorResult As Long = 0) As String()
        
        Dim HDEVINFO_USBPrinterClassDevs As Long
        Dim HDEVINFO_USBClassDevs As Long
        Dim PSP_DEVINFO_DATA_NULL As Long
        Dim PDEVINST_ParentDevInst As Long
        
        Dim typChildDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
        Dim typChildDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim typChildDevInfoData As SP_DEVINFO_DATA
        Dim strChildPath As String
        
        Dim typParentDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
        'Dim typParentDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim typParentDevInfoData As SP_DEVINFO_DATA
        Dim bytParentDeviceInstanceID() As Byte
        'Dim strParentPath As String
        
        Dim strHoldingArray() As String
    
        Dim lngResultingSize As Long
        
        Dim DP_SIZE As Long
        
        If Globals.InIde Then On Error GoTo 0 Else On Error GoTo LocalErrorHandler
        
        DP_SIZE = UBound(typChildDeviceInterfaceDetailData.DataPath)
        
        ReDim bytParentDeviceInstanceID(DP_SIZE) As Byte
        
        Const MIN_SIZE = 5
        Const CR_SUCCESS = 0
        Const ERROR_NO_MORE_ITEMS = 259
    
        Dim lngDeviceInterfaceIndex As Long
        Dim lngDeviceInterfaceCount As Long
            
        ' Fill in initial sizes for structures
        typChildDeviceInterfaceData.cbSize = Len(typChildDeviceInterfaceData)
        typChildDevInfoData.cbSize = Len(typChildDevInfoData)
        
        ' Fill in initial sizes for structures
        typParentDeviceInterfaceData.cbSize = Len(typParentDeviceInterfaceData)
        typParentDevInfoData.cbSize = Len(typParentDevInfoData)
    
        lngErrorResult = 0
    
        Do
            
            ' Create initial device information lists - one for USB Printers, one for generic USB devices
            HDEVINFO_USBPrinterClassDevs = SetupDiGetClassDevs(PrinterGUID, 0, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
            HDEVINFO_USBClassDevs = SetupDiGetClassDevs(USBStackGUID, 0, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
            
            ' If either is invalid, give up
            If HDEVINFO_USBPrinterClassDevs = INVALID_HANDLE_VALUE Then Exit Do
            If HDEVINFO_USBClassDevs = INVALID_HANDLE_VALUE Then Exit Do
            
            ' Count how many USB printer devices we have
            Do While SetupDiEnumDeviceInterfaces(HDEVINFO_USBPrinterClassDevs, PSP_DEVINFO_DATA_NULL, PrinterGUID, lngDeviceInterfaceCount, typChildDeviceInterfaceData)
                lngDeviceInterfaceCount = lngDeviceInterfaceCount + 1
            Loop
        
            ' If we have zero, or we had an error, give up
            If Err.LastDllError <> ERROR_NO_MORE_ITEMS Or lngDeviceInterfaceCount = 0 Then Exit Do
            
            ReDim strHoldingArray(0 To lngDeviceInterfaceCount - 1, 0 To 1) As String
            
            ' Interate over each device
            Do While SetupDiEnumDeviceInterfaces(HDEVINFO_USBPrinterClassDevs, PSP_DEVINFO_DATA_NULL, PrinterGUID, lngDeviceInterfaceIndex, typChildDeviceInterfaceData)
                
                ' You must setup this structure to the fixed size, not the total size. The fixed size is 5 bytes.
                typChildDeviceInterfaceDetailData.cbSize = MIN_SIZE
                ZeroMemory typChildDeviceInterfaceDetailData.DataPath(0), DP_SIZE
                
                ' Get the child's interface detail (path)
                If False = SetupDiGetDeviceInterfaceDetail(HDEVINFO_USBPrinterClassDevs, typChildDeviceInterfaceData, typChildDeviceInterfaceDetailData, DP_SIZE, lngResultingSize, typChildDevInfoData) Then
                    Exit Do
                End If
                
                ' Generate the Child's path
                strChildPath = StrConv(typChildDeviceInterfaceDetailData.DataPath, vbUnicode)
                strChildPath = Left(strChildPath, lngResultingSize - MIN_SIZE)
                
                Dim varResult As Variant
                Dim typSP As typSP_DEVINFO_DATA
                
                CopyMemory typSP.lSize, typChildDevInfoData.cbSize, typChildDevInfoData.cbSize
                
                If SetupDiGetDeviceRegistryProperty(HDEVINFO_USBPrinterClassDevs, typSP, SPDRP_DRIVER, varResult) = False Then
                    Exit Do
                End If
                
                
                ' Get the parent's Device Instance Handle
                If CR_SUCCESS <> CM_Get_Parent(PDEVINST_ParentDevInst, typChildDevInfoData.hDevInst, 0) Then
                    Exit Do
                End If
                           
                ' Clear the Parent's device ID
                'ZeroMemory bytParentDeviceInstanceID(0), DP_SIZE
                'lngResultingSize = 0
                                        
                ' Get the Parentn's Device Instance ID string
                'If CR_SUCCESS <> CM_Get_Device_ID(PDEVINST_ParentDevInst, bytParentDeviceInstanceID(0), DP_SIZE, 0) Then
                '    Exit Do
                'End If
                
                ' From that string get a Device Info Data structure, and add it to the USB Class device information list
                ' This will also generate us our parent's device information data
                'If False = SetupDiOpenDeviceInfo(HDEVINFO_USBClassDevs, bytParentDeviceInstanceID(0), 0, 0, typParentDevInfoData) Then
                '    Exit Do
                'End If
        
                ' Enumerate the device we just added to get the parent's device interface data
                'If False = SetupDiEnumDeviceInterfacesWithInfoPtr(HDEVINFO_USBClassDevs, typParentDevInfoData, USBStackGUID, 0, typParentDeviceInterfaceData) Then
                '    Exit Do
                'End If
        
                ' Clear the structure
                'typParentDeviceInterfaceDetailData.cbSize = MIN_SIZE
                'ZeroMemory typParentDeviceInterfaceDetailData.DataPath(0), DP_SIZE
        
                ' Get the parent's interface detail (path)
                'If False = SetupDiGetDeviceInterfaceDetail(HDEVINFO_USBClassDevs, typParentDeviceInterfaceData, typParentDeviceInterfaceDetailData, DP_SIZE, lngResultingSize, typParentDevInfoData) Then
                '    Exit Do
                'End If
        
                ' Generate the Parent's path
                'strParentPath = StrConv(typParentDeviceInterfaceDetailData.DataPath, vbUnicode)
                'strParentPath = Left(strParentPath, lngResultingSize - MIN_SIZE)
        
                strHoldingArray(lngDeviceInterfaceIndex, 0) = strChildPath
                strHoldingArray(lngDeviceInterfaceIndex, 1) = varResult
                
                lngDeviceInterfaceIndex = lngDeviceInterfaceIndex + 1
                
            Loop
        
            Exit Do
        Loop
    
        lngErrorResult = Err.LastDllError
    
        SetupDiDestroyDeviceInfoList HDEVINFO_USBClassDevs
        SetupDiDestroyDeviceInfoList HDEVINFO_USBPrinterClassDevs
        
        CreateListOfUSBPrinters = strHoldingArray
        
    Exit Function
    
    LocalErrorHandler:
      
      If GlobalError("clsCommuncation:CreateListOfUSBPrinters", Err.Number, Err.Source, Err.Description) = 1 Then Resume Next
            
    End Function
    This mdUsbPrinters.bas is a complete and independent reimplementation of the ideas of the code above (mosting fiddling with setupapi.dll and cfgmgr32.dll APIs) but the whole gist can be compiled to a useful USB printers dumping utility out of the box.

    The code is much more succint and successfully maps a printer name from Printers collection (or direct USB001 port name) to the so called Win32 Device Path like \\?\usb#vid_20d1&pid_0700#2024120147#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}. This path can be used with CreateFile API to "open" a file handle to the USB device/printer and much like COM serial ports to send and receive data in similar fashion.

    Upon device path discovery the sample sends "~HS" status command for Zebra printers (and most other models) and reads/receives correct info using standard ReadFile API call.

    Edit: USB printer's device path from GetUsbDevicePath function can also be used w/ VB's standard I/O statements just fine i.e. Open, Put, Get, Input, Close, etc. work.

    cheers,
    </wqw>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width