Reading from a USB device

Heiko 1,291 Reputation points
2023-04-03T11:26:25.72+00:00

Hello,

I want to read the driectory tree from a USB device that is not a pure storage device, but a camera, smartphone or tablet. Unfortunately, it makes a difference on which OS I run the program. On Windows 8.1 Home x64 I get all subdirectories and files, while on Windows 10/11 Pro x64 (in VMWare) I only get the first level directories, so no deeper subdirectories and no files. In Windows Explorer, all subdirectories and files are displayed on Windows 8.1/10/11. What can be the reason that I can't read deeper items under Windows 10/11?

Output Windows 10/11:

FinePix F30
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04cb&pid_019b#592d313130300605257b2330200e91#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
  xD Picture Card

Output Windows 8.1:

FinePix F30
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_04cb&pid_019b#592d313130300605257b2330200e91#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
  xD Picture Card
    DCIM
      999_FUJI
        DSCF5271.JPG
        DSCF5272.JPG
        DSCF5273.JPG
        ...
public partial class MainWindow : Window
{
	private int	Lines;

	public MainWindow()
	{
		InitializeComponent();
		PrintDeviceTree();
	}

	private void PrintDeviceTree()
	{
		// Add COM reference 'Microsoft Shell Controls And Automation'.
		Shell32.Shell	shell = new Shell32.Shell();
		Shell32.Folder	folder;
		string			root = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";	// 'This PC'

		folder = shell.NameSpace(root);
		Lines = 0;
		foreach (Shell32.FolderItem item in folder.Items())
		{
			if (!IsDevicePath(item.Path))
				continue;

			Print("-------------------------");
			Print(item.Name);
			Print(item.Path);
			PrintDevice_Recursive(shell, item, 1);
		}
	}

	private void PrintDevice_Recursive(Shell32.Shell shell, Shell32.FolderItem parent, int indent)
	{
		if (!parent.IsFolder)
			return;

		Shell32.Folder	folder = shell.NameSpace(parent.Path);

		if (folder == null)
			return;

		Action	printIndent = () =>
		    {
			    if (indent > 0)
				    textBox.Text += new String(' ', indent * 2);
		    };

		foreach (Shell32.FolderItem item in folder.Items())
		{
			if (Lines > 500)
				return;

			printIndent();
			Print(item.Name);
			if (item.IsFolder)
				PrintDevice_Recursive(shell, item, indent + 1);
		}
	}

	private static bool IsDevicePath(string path)
	{
		// Sample 'Windows Phone' with 2 directories:
		// ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_045e&pid_0a00&mi_00#7&19daf175&1&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}
		// ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_045e&pid_0a00&mi_00#7&19daf175&1&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,MTP Volume - 65537,7818182656}
		// ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_045e&pid_0a00&mi_00#7&19daf175&1&0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{20001,MTP Volume - 131073,31426871296}

		if (String.IsNullOrWhiteSpace(path) || path.Length < 50 || !path.StartsWith("::{", StringComparison.OrdinalIgnoreCase))
			return false;

		int	pos = path.IndexOf('}');

		if (pos < 0)
			return false;

		pos++;
		if (pos == path.Length || String.Compare(path, pos, @"\\\?\usb#", 0, @"\\\?\usb#".Length, StringComparison.OrdinalIgnoreCase) != 0)
			return false;

		return true;
	}

	private void Print(string text)
	{
		textBox.Text += text + "\r\n";
		Lines++;
	}
}

Developer technologies | Windows Presentation Foundation
Windows development | Windows API - Win32
Windows for business | Windows Client for IT Pros | User experience | Other
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 90,686 Reputation points
    2023-04-03T14:28:41.2+00:00

    It works for me on Windows 10 22H2 with INamespaceWalk

    Test with a phone (WPD), depth = 4 =>

        public enum HRESULT : int
        {
            S_OK = 0,
            S_FALSE = 1,
            E_NOINTERFACE = unchecked((int)0x80004002),
            E_NOTIMPL = unchecked((int)0x80004001),
            E_FAIL = unchecked((int)0x80004005),
            E_UNEXPECTED = unchecked((int)0x8000FFFF),
            E_OUTOFMEMORY = unchecked((int)0x8007000E)
        }
    
        [ComImportAttribute()]
        [GuidAttribute("d92995f8-cf5e-4a76-bf59-ead39ea2b97e")]
        [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface INamespaceWalkCB
        {
            void FoundItem([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            void EnterFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            void LeaveFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            void InitializeProgressDialog(StringBuilder ppszTitle, StringBuilder ppszCancel);
        }
    
        [ComImportAttribute()]
        [GuidAttribute("7ac7492b-c38e-438a-87db-68737844ff70")]
        [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface INamespaceWalkCB2 : INamespaceWalkCB
        {
            #region INamespaceWalkCB
            new void FoundItem([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            new void EnterFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            new void LeaveFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl);
            new void InitializeProgressDialog(StringBuilder ppszTitle, StringBuilder ppszCancel);
            #endregion
    
            void WalkComplete(HRESULT hr);
        }
    
        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E6-0000-0000-C000-000000000046")]
        public interface IShellFolder
        {
            HRESULT ParseDisplayName(IntPtr hwnd,
                // IBindCtx pbc,
                IntPtr pbc,
                [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [In, Out] ref uint pchEaten, out IntPtr ppidl, [In, Out] ref SFGAO pdwAttributes);
            HRESULT EnumObjects(IntPtr hwnd, SHCONTF grfFlags, out IEnumIDList ppenumIDList);
            HRESULT BindToObject(IntPtr pidl,
                //IBindCtx pbc,
                IntPtr pbc,
                [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv);
            HRESULT BindToStorage(IntPtr pidl, IntPtr pbc, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv);
            HRESULT CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);
            HRESULT CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv);
            HRESULT GetAttributesOf(uint cidl, IntPtr apidl, [In, Out] ref SFGAO rgfInOut);
            //HRESULT GetUIObjectOf(IntPtr hwndOwner, uint cidl, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 1)] IntPtr apidl,
            //    [In] ref Guid riid, [In, Out] ref uint rgfReserved, [MarshalAs(UnmanagedType.Interface)] out object ppv);
            HRESULT GetUIObjectOf(IntPtr hwndOwner, uint cidl, ref IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);
            HRESULT GetDisplayNameOf(IntPtr pidl, SHGDNF uFlags, out STRRET pName);
            HRESULT SetNameOf(IntPtr hwnd, IntPtr pidl, [MarshalAs(UnmanagedType.LPWStr)] string pszName, SHGDNF uFlags, out IntPtr ppidlOut);
        }
    
        [Flags]
        public enum SHCONTF : ushort
        {
            SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
            SHCONTF_FOLDERS = 0x0020,
            SHCONTF_NONFOLDERS = 0x0040,
            SHCONTF_INCLUDEHIDDEN = 0x0080,
            SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
            SHCONTF_NETPRINTERSRCH = 0x0200,
            SHCONTF_SHAREABLE = 0x0400,
            SHCONTF_STORAGE = 0x0800,
            SHCONTF_NAVIGATION_ENUM = 0x1000,
            SHCONTF_FASTITEMS = 0x2000,
            SHCONTF_FLATLIST = 0x4000,
            SHCONTF_ENABLE_ASYNC = 0x8000
        }
    
        [Flags]
        public enum SFGAO : uint
        {
            CANCOPY = 0x00000001,
            CANMOVE = 0x00000002,
            CANLINK = 0x00000004,
            STORAGE = 0x00000008,
            CANRENAME = 0x00000010,
            CANDELETE = 0x00000020,
            HASPROPSHEET = 0x00000040,
            DROPTARGET = 0x00000100,
            CAPABILITYMASK = 0x00000177,
            ENCRYPTED = 0x00002000,
            ISSLOW = 0x00004000,
            GHOSTED = 0x00008000,
            LINK = 0x00010000,
            SHARE = 0x00020000,
            READONLY = 0x00040000,
            HIDDEN = 0x00080000,
            DISPLAYATTRMASK = 0x000FC000,
            STREAM = 0x00400000,
            STORAGEANCESTOR = 0x00800000,
            VALIDATE = 0x01000000,
            REMOVABLE = 0x02000000,
            COMPRESSED = 0x04000000,
            BROWSABLE = 0x08000000,
            FILESYSANCESTOR = 0x10000000,
            FOLDER = 0x20000000,
            FILESYSTEM = 0x40000000,
            HASSUBFOLDER = 0x80000000,
            CONTENTSMASK = 0x80000000,
            STORAGECAPMASK = 0x70C50008,
            PKEYSFGAOMASK = 0x81044000
        }
    
        public enum SHGDNF
        {
            SHGDN_NORMAL = 0,
            SHGDN_INFOLDER = 0x1,
            SHGDN_FOREDITING = 0x1000,
            SHGDN_FORADDRESSBAR = 0x4000,
            SHGDN_FORPARSING = 0x8000
        }
    
        [StructLayout(LayoutKind.Explicit, Size = 264)]
        public struct STRRET
        {
            [FieldOffset(0)]
            //One of the STRRET_* values
            public uint uType;
            [FieldOffset(4)]
            //must be freed by caller of GetDisplayNameOf
            public IntPtr pOleStr;
            //  <FieldOffset(4)> Public pStr As IntPtr      'NOT USED
            [FieldOffset(4)]
            //Offset into SHITEMID
            public uint uOffset;
            [FieldOffset(4)]
            //Buffer to fill in (ANSI)
            public IntPtr cString;
        }
    
        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F2-0000-0000-C000-000000000046")]
        public interface IEnumIDList
        {
            [PreserveSig()]
            HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched);
            [PreserveSig()]
            HRESULT Skip(uint celt);
            void Reset();
            [return: MarshalAs(UnmanagedType.Interface)]
            IEnumIDList Clone();
        }
    
        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("57ced8a7-3f4a-432c-9350-30f24483f74f")]
        public interface INamespaceWalk
        {
            HRESULT Walk(IntPtr punkToWalk, int dwFlags, int cDepth, [MarshalAs(UnmanagedType.Interface)] INamespaceWalkCB pnswcb);
            HRESULT GetIDArrayResult(out uint pcItems, out IntPtr prgpidl);
        }
    
        public enum NAMESPACEWALKFLAG
        {
            NSWF_DEFAULT = 0,
            NSWF_NONE_IMPLIES_ALL = 0x1,
            NSWF_ONE_IMPLIES_ALL = 0x2,
            NSWF_DONT_TRAVERSE_LINKS = 0x4,
            NSWF_DONT_ACCUMULATE_RESULT = 0x8,
            NSWF_TRAVERSE_STREAM_JUNCTIONS = 0x10,
            NSWF_FILESYSTEM_ONLY = 0x20,
            NSWF_SHOW_PROGRESS = 0x40,
            NSWF_FLAG_VIEWORDER = 0x80,
            NSWF_IGNORE_AUTOPLAY_HIDA = 0x100,
            NSWF_ASYNC = 0x200,
            NSWF_DONT_RESOLVE_LINKS = 0x400,
            NSWF_ACCUMULATE_FOLDERS = 0x800,
            NSWF_DONT_SORT = 0x1000,
            NSWF_USE_TRANSFER_MEDIUM = 0x2000,
            NSWF_DONT_TRAVERSE_STREAM_JUNCTIONS = 0x4000,
            NSWF_ANY_IMPLIES_ALL = 0x8000
        };
    
        [ComImport()]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
        public interface IShellItem
        {
            [PreserveSig()]
            HRESULT BindToHandler(IntPtr pbc, ref Guid bhid, ref Guid riid, ref IntPtr ppv);
            HRESULT GetParent(ref IShellItem ppsi);
            HRESULT GetDisplayName(SIGDN sigdnName, ref System.Text.StringBuilder ppszName);
            HRESULT GetAttributes(uint sfgaoMask, ref uint psfgaoAttribs);
            HRESULT Compare(IShellItem psi, uint hint, ref int piOrder);
        }
    
        public enum SIGDN : int
        {
            SIGDN_NORMALDISPLAY = 0x0,
            SIGDN_PARENTRELATIVEPARSING = unchecked((int)0x80018001),
            SIGDN_DESKTOPABSOLUTEPARSING = unchecked((int)0x80028000),
            SIGDN_PARENTRELATIVEEDITING = unchecked((int)0x80031001),
            SIGDN_DESKTOPABSOLUTEEDITING = unchecked((int)0x8004C000),
            SIGDN_FILESYSPATH = unchecked((int)0x80058000),
            SIGDN_URL = unchecked((int)0x80068000),
            SIGDN_PARENTRELATIVEFORADDRESSBAR = unchecked((int)0x8007C001),
            SIGDN_PARENTRELATIVE = unchecked((int)0x80080001)
        }
      
    
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                // WPD
                NamespaceWalk nw = new NamespaceWalk("shell:::{35786D3C-B075-49b9-88DD-029876E11C01}", 4);
            }
        }
    
        public class NamespaceWalk : INamespaceWalkCB2
        {
            [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern HRESULT SHCreateItemFromParsingName(string pszPath, IntPtr pbc, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
    
            [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern HRESULT StrRetToBuf(ref STRRET pstr, IntPtr pidl, StringBuilder pszBuf, [MarshalAs(UnmanagedType.U4)] uint cchBuf);
    
            private static Guid CLSID_NamespaceWalker = new Guid("72eb61e0-8672-4303-9175-f2e4c68b2e7c");
            public NamespaceWalk(string sPath, int nDepth = 5)
            {
                Type NamespaceWalkerType = Type.GetTypeFromCLSID(CLSID_NamespaceWalker, true);
                object oNamespaceWalk = Activator.CreateInstance(NamespaceWalkerType);
                INamespaceWalk pNamespaceWalk = (INamespaceWalk)oNamespaceWalk;
                if (pNamespaceWalk != null)
                {
                    IShellItem pShellItem = null;
                    HRESULT hr = SHCreateItemFromParsingName(sPath, IntPtr.Zero, typeof(IShellItem).GUID, out pShellItem);
                    if (hr == HRESULT.S_OK)
                    {
                        IntPtr pUnk = Marshal.GetIUnknownForObject(pShellItem);
                        hr = pNamespaceWalk.Walk(pUnk, (int)(NAMESPACEWALKFLAG.NSWF_DONT_TRAVERSE_LINKS | NAMESPACEWALKFLAG.NSWF_DONT_ACCUMULATE_RESULT), nDepth, this);
                     }
                }
            }
    
            string sIndent = "";
    
            void INamespaceWalkCB.EnterFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {
                STRRET strretFolderName;
                HRESULT hr = psf.GetDisplayNameOf(pidl, SHGDNF.SHGDN_NORMAL, out strretFolderName);
                string sDisplayName = null;
                StringBuilder sbDisplayName = default(StringBuilder);
                sbDisplayName = new StringBuilder(256);
                StrRetToBuf(ref strretFolderName, pidl, sbDisplayName, (uint)sbDisplayName.Capacity);
                sDisplayName = sbDisplayName.ToString();          
                Console.WriteLine("{0}Folder : {1}", sIndent, sDisplayName);
                sIndent += "-";
            }
    
            void INamespaceWalkCB2.EnterFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {           
               
            }
    
            void INamespaceWalkCB.FoundItem([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {
                STRRET strretFolderName;
                HRESULT hr = psf.GetDisplayNameOf(pidl, SHGDNF.SHGDN_FOREDITING , out strretFolderName);
                string sDisplayName = null;
                StringBuilder sbDisplayName = default(StringBuilder);
                sbDisplayName = new StringBuilder(256);
                StrRetToBuf(ref strretFolderName, pidl, sbDisplayName, (uint)sbDisplayName.Capacity);
                sDisplayName = sbDisplayName.ToString();
                Console.WriteLine("{0}Item : {1}", sIndent, sDisplayName);
            }
    
            void INamespaceWalkCB2.FoundItem([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {
               
            }
      
            void INamespaceWalkCB.InitializeProgressDialog(StringBuilder ppszTitle, StringBuilder ppszCancel)
            {
               
            }
    
            void INamespaceWalkCB2.InitializeProgressDialog(StringBuilder ppszTitle, StringBuilder ppszCancel)
            {
               
            }
    
            void INamespaceWalkCB.LeaveFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {
                STRRET strretFolderName;
                HRESULT hr = psf.GetDisplayNameOf(pidl, SHGDNF.SHGDN_FOREDITING, out strretFolderName);
                string sDisplayName = null;
                StringBuilder sbDisplayName = default(StringBuilder);
                sbDisplayName = new StringBuilder(256);
                StrRetToBuf(ref strretFolderName, pidl, sbDisplayName, (uint)sbDisplayName.Capacity);          
                sIndent = sIndent.Substring(0, sIndent.Length - 1);
                sDisplayName = sbDisplayName.ToString();           
            }
    
            void INamespaceWalkCB2.LeaveFolder([MarshalAs(UnmanagedType.Interface)] IShellFolder psf, IntPtr pidl)
            {
                
            }
    
            void INamespaceWalkCB2.WalkComplete(HRESULT hr)
            {
               
            }
        }
    

0 additional answers

Sort by: Most helpful

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.