57 * a series of identifiers and can be either relative to the desktop 58 * (an absolute PIDL), or relative to the shell folder that contains them. 59 * Some Win32 functions can take absolute or relative PIDL values, and 60 * others can only accept relative values. 61 * <BR> 62 * The second data structure is an IShellFolder COM interface. Using 63 * this interface, one can enumerate the relative PIDLs in a shell 64 * folder, get attributes, etc. 65 * <BR> 66 * All Win32ShellFolder2 objects which are folder types (even non-file 67 * system folders) contain an IShellFolder object. Files are named in 68 * directories via relative PIDLs. 69 * 70 * @author Michael Martak 71 * @author Leif Samuelsson 72 * @author Kenneth Russell 73 * @since 1.4 */ 74 @SuppressWarnings("serial") // JDK-implementation class 75 final class Win32ShellFolder2 extends ShellFolder { 76 77 private static native void initIDs(); 78 79 static { 80 initIDs(); 81 } 82 83 // Win32 Shell Folder Constants 84 public static final int DESKTOP = 0x0000; 85 public static final int INTERNET = 0x0001; 86 public static final int PROGRAMS = 0x0002; 87 public static final int CONTROLS = 0x0003; 88 public static final int PRINTERS = 0x0004; 89 public static final int PERSONAL = 0x0005; 90 public static final int FAVORITES = 0x0006; 91 public static final int STARTUP = 0x0007; 92 public static final int RECENT = 0x0008; 93 public static final int SENDTO = 0x0009; 94 public static final int BITBUCKET = 0x000a; 95 public static final int STARTMENU = 0x000b; 96 public static final int DESKTOPDIRECTORY = 0x0010; 960 961 962 // Icons 963 964 private static Map<Integer, Image> smallSystemImages = new HashMap<>(); 965 private static Map<Integer, Image> largeSystemImages = new HashMap<>(); 966 private static Map<Integer, Image> smallLinkedSystemImages = new HashMap<>(); 967 private static Map<Integer, Image> largeLinkedSystemImages = new HashMap<>(); 968 969 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 970 private static native long getIShellIcon(long pIShellFolder); 971 972 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 973 private static native int getIconIndex(long parentIShellIcon, long relativePIDL); 974 975 // Return the icon of a file system shell folder in the form of an HICON 976 private static native long getIcon(String absolutePath, boolean getLargeIcon); 977 978 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 979 private static native long extractIcon(long parentIShellFolder, long relativePIDL, 980 boolean getLargeIcon, boolean getDefaultIcon); 981 982 // Returns an icon from the Windows system icon list in the form of an HICON 983 private static native long getSystemIcon(int iconID); 984 private static native long getIconResource(String libName, int iconID, 985 int cxDesired, int cyDesired, 986 boolean useVGAColors); 987 // Note: useVGAColors is ignored on XP and later 988 989 // Return the bits from an HICON. This has a side effect of setting 990 // the imageHash variable for efficient caching / comparing. 991 private static native int[] getIconBits(long hIcon); 992 // Dispose the HICON 993 private static native void disposeIcon(long hIcon); 994 995 // Get buttons from native toolbar implementation. 996 static native int[] getStandardViewButton0(int iconIndex, boolean small); 997 998 // Should be called from the COM thread 999 private long getIShellIcon() { 1000 if (pIShellIcon == -1L) { 1001 pIShellIcon = getIShellIcon(getIShellFolder()); 1002 } 1003 1004 return pIShellIcon; 1005 } 1006 1007 private static Image makeIcon(long hIcon, boolean getLargeIcon) { 1008 if (hIcon != 0L && hIcon != -1L) { 1009 // Get the bits. This has the side effect of setting the imageHash value for this object. 1010 final int[] iconBits = getIconBits(hIcon); 1011 if (iconBits != null) { 1012 // icons are always square 1013 final int size = (int) Math.sqrt(iconBits.length); 1014 final int baseSize = getLargeIcon ? 32 : 16; 1015 final BufferedImage img = 1016 new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); 1017 img.setRGB(0, 0, size, size, iconBits, 0, size); 1018 return size == baseSize 1019 ? img 1020 : new MultiResolutionIconImage(baseSize, img); 1021 } 1022 } 1023 return null; 1024 } 1025 1026 1027 /** 1028 * @return The icon image used to display this shell folder 1029 */ 1030 public Image getIcon(final boolean getLargeIcon) { 1031 Image icon = getLargeIcon ? largeIcon : smallIcon; 1032 if (icon == null) { 1033 icon = 1034 invoke(new Callable<Image>() { 1035 public Image call() { 1036 Image newIcon = null; 1037 if (isLink()) { 1038 Win32ShellFolder2 folder = getLinkLocation(false); 1039 if (folder != null && folder.isLibrary()) { 1040 return folder.getIcon(getLargeIcon); 1041 } 1042 } 1043 if (isFileSystem() || isLibrary()) { 1044 long parentIShellIcon = (parent != null) 1045 ? ((Win32ShellFolder2) parent).getIShellIcon() 1046 : 0L; 1047 long relativePIDL = getRelativePIDL(); 1048 1049 // These are cached per type (using the index in the system image list) 1050 int index = getIconIndex(parentIShellIcon, relativePIDL); 1051 if (index > 0) { 1052 Map<Integer, Image> imageCache; 1053 if (isLink()) { 1054 imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; 1055 } else { 1056 imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; 1057 } 1058 newIcon = imageCache.get(Integer.valueOf(index)); 1059 if (newIcon == null) { 1060 long hIcon = getIcon(getAbsolutePath(), getLargeIcon); 1061 newIcon = makeIcon(hIcon, getLargeIcon); 1062 disposeIcon(hIcon); 1063 if (newIcon != null) { 1064 imageCache.put(Integer.valueOf(index), newIcon); 1065 } 1066 } 1067 } 1068 } 1069 1070 if (newIcon == null) { 1071 // These are only cached per object 1072 long hIcon = extractIcon(getParentIShellFolder(), 1073 getRelativePIDL(), getLargeIcon, false); 1074 // E_PENDING: loading can take time so get the default 1075 if(hIcon <= 0) { 1076 hIcon = extractIcon(getParentIShellFolder(), 1077 getRelativePIDL(), getLargeIcon, true); 1078 if(hIcon <= 0) { 1079 if (isDirectory()) { 1080 return getShell32Icon(4, getLargeIcon); 1081 } else { 1082 return getShell32Icon(1, getLargeIcon); 1083 } 1084 } 1085 } 1086 newIcon = makeIcon(hIcon, getLargeIcon); 1087 disposeIcon(hIcon); 1088 } 1089 1090 if (newIcon == null) { 1091 newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon); 1092 } 1093 return newIcon; 1094 } 1095 }); 1096 if (getLargeIcon) { 1097 largeIcon = icon; 1098 } else { 1099 smallIcon = icon; 1100 } 1101 } 1102 return icon; 1103 } 1104 1105 /** 1106 * Gets an icon from the Windows system icon list as an {@code Image} 1107 */ 1108 static Image getSystemIcon(SystemIcon iconType) { 1109 long hIcon = getSystemIcon(iconType.getIconID()); 1110 Image icon = makeIcon(hIcon, true); 1111 disposeIcon(hIcon); 1112 return icon; 1113 } 1114 1115 /** 1116 * Gets an icon from the Windows system icon list as an {@code Image} 1117 */ 1118 static Image getShell32Icon(int iconID, boolean getLargeIcon) { 1119 boolean useVGAColors = true; // Will be ignored on XP and later 1120 1121 int size = getLargeIcon ? 32 : 16; 1122 1123 Toolkit toolkit = Toolkit.getDefaultToolkit(); 1124 String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP"); 1125 if (shellIconBPP != null) { 1126 useVGAColors = shellIconBPP.equals("4"); 1127 } 1128 1129 long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors); 1130 if (hIcon != 0) { 1131 Image icon = makeIcon(hIcon, getLargeIcon); 1132 disposeIcon(hIcon); 1133 return icon; 1134 } 1135 return null; 1136 } 1137 1138 /** 1139 * Returns the canonical form of this abstract pathname. Equivalent to 1140 * <code>new Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>. 1141 * 1142 * @see java.io.File#getCanonicalFile 1143 */ 1144 public File getCanonicalFile() throws IOException { 1145 return this; 1146 } 1147 1148 /* 1149 * Indicates whether this is a special folder (includes My Documents) 1150 */ 1151 public boolean isSpecial() { | 57 * a series of identifiers and can be either relative to the desktop 58 * (an absolute PIDL), or relative to the shell folder that contains them. 59 * Some Win32 functions can take absolute or relative PIDL values, and 60 * others can only accept relative values. 61 * <BR> 62 * The second data structure is an IShellFolder COM interface. Using 63 * this interface, one can enumerate the relative PIDLs in a shell 64 * folder, get attributes, etc. 65 * <BR> 66 * All Win32ShellFolder2 objects which are folder types (even non-file 67 * system folders) contain an IShellFolder object. Files are named in 68 * directories via relative PIDLs. 69 * 70 * @author Michael Martak 71 * @author Leif Samuelsson 72 * @author Kenneth Russell 73 * @since 1.4 */ 74 @SuppressWarnings("serial") // JDK-implementation class 75 final class Win32ShellFolder2 extends ShellFolder { 76 77 static final int SMALL_ICON_SIZE = 16; 78 static final int LARGE_ICON_SIZE = 32; 79 80 static final int FILE_ICON_ID = 1; 81 static final int FOLDER_ICON_ID = 4; 82 83 private static native void initIDs(); 84 85 static { 86 initIDs(); 87 } 88 89 // Win32 Shell Folder Constants 90 public static final int DESKTOP = 0x0000; 91 public static final int INTERNET = 0x0001; 92 public static final int PROGRAMS = 0x0002; 93 public static final int CONTROLS = 0x0003; 94 public static final int PRINTERS = 0x0004; 95 public static final int PERSONAL = 0x0005; 96 public static final int FAVORITES = 0x0006; 97 public static final int STARTUP = 0x0007; 98 public static final int RECENT = 0x0008; 99 public static final int SENDTO = 0x0009; 100 public static final int BITBUCKET = 0x000a; 101 public static final int STARTMENU = 0x000b; 102 public static final int DESKTOPDIRECTORY = 0x0010; 966 967 968 // Icons 969 970 private static Map<Integer, Image> smallSystemImages = new HashMap<>(); 971 private static Map<Integer, Image> largeSystemImages = new HashMap<>(); 972 private static Map<Integer, Image> smallLinkedSystemImages = new HashMap<>(); 973 private static Map<Integer, Image> largeLinkedSystemImages = new HashMap<>(); 974 975 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 976 private static native long getIShellIcon(long pIShellFolder); 977 978 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 979 private static native int getIconIndex(long parentIShellIcon, long relativePIDL); 980 981 // Return the icon of a file system shell folder in the form of an HICON 982 private static native long getIcon(String absolutePath, boolean getLargeIcon); 983 984 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details 985 private static native long extractIcon(long parentIShellFolder, long relativePIDL, 986 int size, boolean getDefaultIcon); 987 988 // Returns an icon from the Windows system icon list in the form of an HICON 989 private static native long getSystemIcon(int iconID); 990 private static native long getIconResource(String libName, int iconID, 991 int cxDesired, int cyDesired, 992 boolean useVGAColors); 993 // Note: useVGAColors is ignored on XP and later 994 995 // Return the bits from an HICON. This has a side effect of setting 996 // the imageHash variable for efficient caching / comparing. 997 private static native int[] getIconBits(long hIcon); 998 // Dispose the HICON 999 private static native void disposeIcon(long hIcon); 1000 1001 // Get buttons from native toolbar implementation. 1002 static native int[] getStandardViewButton0(int iconIndex, boolean small); 1003 1004 // Should be called from the COM thread 1005 private long getIShellIcon() { 1006 if (pIShellIcon == -1L) { 1007 pIShellIcon = getIShellIcon(getIShellFolder()); 1008 } 1009 1010 return pIShellIcon; 1011 } 1012 1013 private static Image makeIcon(long hIcon, int bsize) { 1014 if (hIcon != 0L && hIcon != -1L) { 1015 // Get the bits. This has the side effect of setting the imageHash value for this object. 1016 final int[] iconBits = getIconBits(hIcon); 1017 if (iconBits != null) { 1018 // icons are always square 1019 final int size = (int) Math.sqrt(iconBits.length); 1020 final BufferedImage img = 1021 new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); 1022 img.setRGB(0, 0, size, size, iconBits, 0, size); 1023 return size == bsize 1024 ? img 1025 : new MultiResolutionIconImage(bsize, img); 1026 } 1027 } 1028 return null; 1029 } 1030 1031 public Image getIcon(int size) { 1032 return invoke(() -> { 1033 Image newIcon = null; 1034 if (isLink()) { 1035 Win32ShellFolder2 folder = getLinkLocation(false); 1036 if (folder != null && folder.isLibrary()) { 1037 return folder.getIcon(size); 1038 } 1039 } 1040 long hIcon = extractIcon(getParentIShellFolder(), 1041 getRelativePIDL(), size, false); 1042 // E_PENDING: loading can take time so get the default 1043 if(hIcon <= 0) { 1044 hIcon = extractIcon(getParentIShellFolder(), 1045 getRelativePIDL(), size, true); 1046 if(hIcon <= 0) { 1047 if (isDirectory()) { 1048 return getShell32Icon(FOLDER_ICON_ID, size); 1049 } else { 1050 return getShell32Icon(FILE_ICON_ID, size); 1051 } 1052 } 1053 } 1054 newIcon = makeIcon(hIcon, size); 1055 disposeIcon(hIcon); 1056 return newIcon; 1057 }); 1058 } 1059 1060 /** 1061 * @return The icon image used to display this shell folder 1062 */ 1063 public Image getIcon(final boolean getLargeIcon) { 1064 int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE; 1065 Image icon = getLargeIcon ? largeIcon : smallIcon; 1066 if (icon == null) { 1067 icon = 1068 invoke(new Callable<Image>() { 1069 public Image call() { 1070 Image newIcon = null; 1071 if (isLink()) { 1072 Win32ShellFolder2 folder = getLinkLocation(false); 1073 if (folder != null && folder.isLibrary()) { 1074 return folder.getIcon(getLargeIcon); 1075 } 1076 } 1077 if (isFileSystem() || isLibrary()) { 1078 long parentIShellIcon = (parent != null) 1079 ? ((Win32ShellFolder2) parent).getIShellIcon() 1080 : 0L; 1081 long relativePIDL = getRelativePIDL(); 1082 1083 // These are cached per type (using the index in the system image list) 1084 int index = getIconIndex(parentIShellIcon, relativePIDL); 1085 if (index > 0) { 1086 Map<Integer, Image> imageCache; 1087 if (isLink()) { 1088 imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; 1089 } else { 1090 imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; 1091 } 1092 newIcon = imageCache.get(Integer.valueOf(index)); 1093 if (newIcon == null) { 1094 long hIcon = getIcon(getAbsolutePath(), getLargeIcon); 1095 newIcon = makeIcon(hIcon, size); 1096 disposeIcon(hIcon); 1097 if (newIcon != null) { 1098 imageCache.put(Integer.valueOf(index), newIcon); 1099 } 1100 } 1101 } 1102 } 1103 1104 if (newIcon == null) { 1105 // These are only cached per object 1106 long hIcon = extractIcon(getParentIShellFolder(), 1107 getRelativePIDL(), size, false); 1108 // E_PENDING: loading can take time so get the default 1109 if(hIcon <= 0) { 1110 hIcon = extractIcon(getParentIShellFolder(), 1111 getRelativePIDL(), size, true); 1112 if(hIcon <= 0) { 1113 if (isDirectory()) { 1114 return getShell32Icon(FOLDER_ICON_ID, 1115 size); 1116 } else { 1117 return getShell32Icon(FILE_ICON_ID, 1118 size); 1119 } 1120 } 1121 } 1122 newIcon = makeIcon(hIcon, size); 1123 disposeIcon(hIcon); 1124 } 1125 1126 return newIcon; 1127 } 1128 }); 1129 } 1130 return icon; 1131 } 1132 1133 /** 1134 * Gets an icon from the Windows system icon list as an {@code Image} 1135 */ 1136 static Image getSystemIcon(SystemIcon iconType) { 1137 long hIcon = getSystemIcon(iconType.getIconID()); 1138 Image icon = makeIcon(hIcon, LARGE_ICON_SIZE); 1139 disposeIcon(hIcon); 1140 return icon; 1141 } 1142 1143 /** 1144 * Gets an icon from the Windows system icon list as an {@code Image} 1145 */ 1146 static Image getShell32Icon(int iconID, int size) { 1147 boolean useVGAColors = true; // Will be ignored on XP and later 1148 1149 Toolkit toolkit = Toolkit.getDefaultToolkit(); 1150 String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP"); 1151 if (shellIconBPP != null) { 1152 useVGAColors = shellIconBPP.equals("4"); 1153 } 1154 1155 long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors); 1156 if (hIcon != 0) { 1157 Image icon = makeIcon(hIcon, size); 1158 disposeIcon(hIcon); 1159 return icon; 1160 } 1161 return null; 1162 } 1163 1164 /** 1165 * Returns the canonical form of this abstract pathname. Equivalent to 1166 * <code>new Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>. 1167 * 1168 * @see java.io.File#getCanonicalFile 1169 */ 1170 public File getCanonicalFile() throws IOException { 1171 return this; 1172 } 1173 1174 /* 1175 * Indicates whether this is a special folder (includes My Documents) 1176 */ 1177 public boolean isSpecial() { |