private IEnumerable <ItemInfo> EnumHierarchyItems(IVsHierarchy hierarchy, uint itemId, int level, string project, TinyList <string> logicalPath) { var currentName = hierarchy.GetProp <string>(itemId, __VSHPROPID.VSHPROPID_Name); // Enumerate nested var nested = hierarchy.GetNested(itemId); if (nested != null) { if (level == 1) { project = currentName; } foreach (var item in EnumHierarchyItems(nested.Item1, nested.Item2, level, project, logicalPath)) { yield return(item); } yield break; } if (SkipItem(currentName)) { yield break; } yield return(new ItemInfo { Name = currentName, ProjectName = project, IconIndex = IconCache.Add(hierarchy, itemId), LogicalPath = logicalPath.Foldr(new StringBuilder(), (s, b) => b.Append('/') .Append(s)).Append('/').Append(currentName).ToString(), Path = (level > 0 && itemId != VSConstants.VSITEMID_NIL && itemId != VSConstants.VSITEMID_ROOT) ? hierarchy.GetCanonicalName(itemId) : null, }); // Enumerate normal children var hasSideEffects = hierarchy.GetProp <object>(itemId, __VSHPROPID.VSHPROPID_HasEnumerationSideEffects); if (hasSideEffects as bool? == true) { // Enumerate slow var path = hierarchy.GetCanonicalName(itemId).TrimEnd('/', '\\'); if (Directory.Exists(path)) { if (!SkipItem(currentName)) { foreach (var item in EnumDirectory(path, project, logicalPath)) { yield return(item); } } } else { // TODO: notify user somehow } } else { // Enumerate fast // maybe use __VSHPROPID.VSHPROPID_FirstVisibleChild ? var node = hierarchy.GetProp <object>(itemId, __VSHPROPID.VSHPROPID_FirstChild); if (level > 1) { logicalPath = logicalPath.Cons(currentName); } while (node != null) { var nodeId = (uint)(int)node; if (nodeId == VSConstants.VSITEMID_NIL) { break; } foreach (var item in EnumHierarchyItems(hierarchy, nodeId, level + 1, project, logicalPath)) { yield return(item); } node = hierarchy.GetProp <object>(nodeId, __VSHPROPID.VSHPROPID_NextSibling); } } }