internal static string?GetShellFileTypeAndIcon(string fileName, bool useExistingFile, IconOptions iconOptions, Action <IntPtr>?useIconHandle) { Conditions.RequireString(fileName, nameof(fileName)); Conditions.RequireArgument( (iconOptions == IconOptions.None && useIconHandle == null) || (iconOptions != IconOptions.None && useIconHandle != null), "The iconOptions and useIconHandle arguments must be compatible."); SHFILEINFO info = default; int cbFileInfo = Marshal.SizeOf(info); SHGFI flags = SHGFI.TypeName; int fileAttributes = 0; if (!useExistingFile) { flags |= SHGFI.UseFileAttributes; const int FILE_ATTRIBUTE_NORMAL = 128; const int FILE_ATTRIBUTE_DIRECTORY = 16; // http://stackoverflow.com/questions/1599235/how-do-i-fetch-the-folder-icon-on-windows-7-using-shell32-shgetfileinfo fileAttributes = iconOptions.HasFlag(IconOptions.Folder) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; } bool useIcon = iconOptions != IconOptions.None; if (useIcon) { flags |= SHGFI.Icon; // The Small and Large options are mutually exclusive. If they specify neither or both, then we'll default to small. if (iconOptions.HasFlag(IconOptions.Small) || !iconOptions.HasFlag(IconOptions.Large)) { flags |= SHGFI.SmallIcon; } else { flags |= SHGFI.LargeIcon; } if (iconOptions.HasFlag(IconOptions.ShellSize)) { flags |= SHGFI.ShellIconSize; } if (iconOptions.HasFlag(IconOptions.Open)) { flags |= SHGFI.OpenIcon; } if (iconOptions.HasFlag(IconOptions.Shortcut)) { flags |= SHGFI.LinkOverlay; } if (iconOptions.HasFlag(IconOptions.Selected)) { flags |= SHGFI.Selected; } } string?result = null; if (SHGetFileInfo(fileName, fileAttributes, out info, (uint)cbFileInfo, flags) != IntPtr.Zero) { result = info.szTypeName; if (useIcon && useIconHandle != null) { // The caller has to make a copy (e.g., Icon.FromHandle(hIcon).Clone()). useIconHandle(info.hIcon); DestroyIcon(info.hIcon); } } return(result); }