How to iterate through files on USB device with Visual C++

Nigel Hoult 0 Reputation points
2025-02-12T15:45:43.4933333+00:00

I'm trying to write a program that will open the root directory of a USB device that appears in Windows Explorer as a file system (specifically, an iPhone) and then iterate through the files on it. I have successfully used SetupDiGetClassDevs, SetupDiEnumInterfaceDevice and SetupDiGetDeviceInterfaceDetail (with device class GUID_DEVINTERFACE_USB_DEVICE) to iterate through the USB devices, and by looking in the DevicePath for the "vid" and "uid" strings to identify which one is the iPhone. The path that I get is of the form \?\usb#vid_05ac&pid_12a8#00008110001240aa3e83401e#{a5dcbf10-6530-11d2-901f-00c04fb951ed}

What I then want to do is to append "*" to this and pass it to FindFirstFile; however, this always fails; the error returned by GetLastError is 1 (ERROR_INVALID_FUNCTION), which is not much help. Can anyone explain what I'm doing wrong, please?

Visual Studio
Visual Studio
A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.
5,433 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,856 questions
{count} votes

3 answers

Sort by: Most helpful
  1. Nigel Hoult 0 Reputation points
    2025-02-12T23:19:43.2266667+00:00

    Thanks for the responses. To answer the second one first, this is a typo on my part; I did indeed mean "*", and that is what didn't work.

    I'm not sure how to interpret shell:::{35786D3C-B075-49b9-88DD-029876E11C01} but I have tried using Shell interfaces (I rejected the WPD API as too complex and poorly explained), by interating down from "Computer" until I find a drive with the display name "Apple iPhone" (is there a cleaner way?). This is promising so far, in that I am able to drill down through the subdirectories on the phone; however, I haven't yet got as far as trying to read individual files, and the lack of good sample code makes it a slow process. Currently I'm using BindToObject to get the subfolder's IShellInterface, but I wonder whether I should be using the IStorageInterface, members OpenStream and/or OpenStorage; clearly I will have to use something like that to read individual files.

    While experimenting with this, I did notice something strange in Windows Explorer. First of all, the context menu on (for example) a JPG image on the iPhone is different from that on a similar file elsewhere, both in contents (no "open with", for example) and format (closer spaced and without the "cut", "copy" etc buttons at top or bottom). Secondly, if I right-click a file on the iPhone and select "Properties", the location is shown as (for example) This PC\Apple iPhone\Internal Storage\200503__ (which is how it appears in Explorer), but if I open it in its default application (which in my case is Irfanview), its folder is shown as C:\Users<name>\AppData\Local\Microsoft\Windows\INetCache<random string>\ which suggests the Windows has for some reason made a copy in the background.

    0 comments No comments

  2. Castorix31 86,981 Reputation points
    2025-02-13T08:07:03.8766667+00:00

    A way is with INamespaceWalk interface

    There are samples in MS SDK like https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/winui/shell/appplatform/ShellLibraryBackup

    You can put as root shell:::{35786D3C-B075-49b9-88DD-029876E11C01}, with SHCreateItemFromParsingName to get IShellItem


  3. Nigel Hoult 0 Reputation points
    2025-02-13T12:53:55.3666667+00:00

    I tried INamespaceWalk (admittedly without the "async" flag which was used in the example since I was only walking through a very small number of objects) but couldn't get it to work; it always returned "cancelled by user".

    I made some further progress with the shell interfaces, and was able to get down to the individual files I wanted to copy, but there I hit a problem; I could successfully bind to the IStream interface and get the status (file name, date etc) but hit problems trying to read from the stream. If I tried to read in chunks of 1000 bytes, then the first chunk was read successfully (and almost immediately) but the program hung on subsequent chunks; if I tried to read in chunks of 100000 bytes, the program just hung. The actual file was about 3Mbytes in size. Here is the relevant part of the code (obviously I would add error checking later):

                IStream* pStream = NULL;
    
                BYTE buffer[1000];
    
                ULONG nRead = 0;
    

    // pidlItems has been obtained by enumerating the "non folders" in psfSubFolder; they are JPG files in this case. I tried BindToStorage as well with much the same result.

                hr = psfSubFolder->BindToObject(pidlItems, NULL, IID_IStream, (LPVOID*)&pStream); // returns S_OK
    
                STATSTG st;
    
                SYSTEMTIME syst;
    
                pStream->Stat(&st, 0);
    
                FileTimeToSystemTime(&(st.mtime), &syst);
    
                do
    
                {
    
                     hr = pStream->Read(buffer, 1000, &nRead);
    

    // Clearly I will do something with the data once it's working!

                } 
    
                while (hr == S_OK);
    
                pStream->Release();
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.