8182043: Access to Windows Large Icons

Reviewed-by: aivanov, azvegint, prr
This commit is contained in:
Alexander Zuev 2021-05-27 21:49:20 +00:00
parent 8a31c07598
commit 7f52c50ba3
6 changed files with 370 additions and 81 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package javax.swing.filechooser; package javax.swing.filechooser;
import java.awt.Image; import java.awt.Image;
import java.awt.image.AbstractMultiResolutionImage;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -225,7 +226,7 @@ public abstract class FileSystemView {
* Icon for a file, directory, or folder as it would be displayed in * Icon for a file, directory, or folder as it would be displayed in
* a system file browser. Example from Windows: the "M:\" directory * a system file browser. Example from Windows: the "M:\" directory
* displays a CD-ROM icon. * displays a CD-ROM icon.
* * <p>
* The default implementation gets information from the ShellFolder class. * The default implementation gets information from the ShellFolder class.
* *
* @param f a <code>File</code> object * @param f a <code>File</code> object
@ -255,6 +256,67 @@ public abstract class FileSystemView {
} }
} }
/**
* Returns an icon for a file, directory, or folder as it would be displayed
* in a system file browser for the requested size.
* <p>
* Example: <pre>
* FileSystemView fsv = FileSystemView.getFileSystemView();
* Icon icon = fsv.getSystemIcon(new File("application.exe"), 64, 64);
* JLabel label = new JLabel(icon);
* </pre>
*
* @implSpec The available icons may be platform specific and so the
* available sizes determined by the platform. Therefore an exact match
* for the requested size may not be possible.
*
* The icon returned may be a multi-resolution icon image,
* which allows better support for High DPI environments
* with different scaling factors.
*
* @param f a {@code File} object for which the icon will be retrieved
* @param width width of the icon in user coordinate system.
* @param height height of the icon in user coordinate system.
* @return an icon as it would be displayed by a native file chooser
* or null for a non-existent or inaccessible file.
* @throws IllegalArgumentException if an invalid parameter such
* as a negative size or a null file reference is passed.
* @see JFileChooser#getIcon
* @see AbstractMultiResolutionImage
* @see FileSystemView#getSystemIcon(File)
* @since 17
*/
public Icon getSystemIcon(File f, int width, int height) {
if (height < 1 || width < 1) {
throw new IllegalArgumentException("Icon size can not be below 1");
}
if (f == null) {
throw new IllegalArgumentException("The file reference should not be null");
}
if(!f.exists()) {
return null;
}
ShellFolder sf;
try {
sf = ShellFolder.getShellFolder(f);
} catch (FileNotFoundException e) {
return null;
}
Image img = sf.getIcon(width, height);
if (img != null) {
return new ImageIcon(img, sf.getFolderType());
} else {
return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon"
: "FileView.fileIcon");
}
}
/** /**
* On Windows, a file can appear in multiple folders, other than its * On Windows, a file can appear in multiple folders, other than its
* parent directory in the filesystem. Folder could for example be the * parent directory in the filesystem. Folder could for example be the

View File

@ -207,6 +207,16 @@ public abstract class ShellFolder extends File {
return null; return null;
} }
/**
* Returns the icon of the specified size used to display this shell folder.
*
* @param width width of the icon > 0
* @param height height of the icon > 0
* @return The icon of the specified size used to display this shell folder
*/
public Image getIcon(int width, int height) {
return null;
}
// Static // Static

View File

@ -82,6 +82,16 @@ import javax.swing.SwingConstants;
@SuppressWarnings("serial") // JDK-implementation class @SuppressWarnings("serial") // JDK-implementation class
final class Win32ShellFolder2 extends ShellFolder { final class Win32ShellFolder2 extends ShellFolder {
static final int SMALL_ICON_SIZE = 16;
static final int LARGE_ICON_SIZE = 32;
static final int MIN_QUALITY_ICON = 16;
static final int MAX_QUALITY_ICON = 256;
private final static int[] ICON_RESOLUTIONS
= {16, 24, 32, 48, 64, 72, 96, 128, 256};
static final int FILE_ICON_ID = 1;
static final int FOLDER_ICON_ID = 4;
private static native void initIDs(); private static native void initIDs();
static { static {
@ -991,14 +1001,15 @@ final class Win32ShellFolder2 extends ShellFolder {
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long extractIcon(long parentIShellFolder, long relativePIDL, private static native long extractIcon(long parentIShellFolder, long relativePIDL,
boolean getLargeIcon, boolean getDefaultIcon); int size, boolean getDefaultIcon);
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native boolean hiResIconAvailable(long parentIShellFolder, long relativePIDL);
// Returns an icon from the Windows system icon list in the form of an HICON // Returns an icon from the Windows system icon list in the form of an HICON
private static native long getSystemIcon(int iconID); private static native long getSystemIcon(int iconID);
private static native long getIconResource(String libName, int iconID, private static native long getIconResource(String libName, int iconID,
int cxDesired, int cyDesired, int cxDesired, int cyDesired);
boolean useVGAColors);
// Note: useVGAColors is ignored on XP and later
// Return the bits from an HICON. This has a side effect of setting // Return the bits from an HICON. This has a side effect of setting
// the imageHash variable for efficient caching / comparing. // the imageHash variable for efficient caching / comparing.
@ -1018,20 +1029,17 @@ final class Win32ShellFolder2 extends ShellFolder {
return pIShellIcon; return pIShellIcon;
} }
private static Image makeIcon(long hIcon, boolean getLargeIcon) { private static Image makeIcon(long hIcon) {
if (hIcon != 0L && hIcon != -1L) { if (hIcon != 0L && hIcon != -1L) {
// Get the bits. This has the side effect of setting the imageHash value for this object. // Get the bits. This has the side effect of setting the imageHash value for this object.
final int[] iconBits = getIconBits(hIcon); final int[] iconBits = getIconBits(hIcon);
if (iconBits != null) { if (iconBits != null) {
// icons are always square // icons are always square
final int size = (int) Math.sqrt(iconBits.length); final int iconSize = (int) Math.sqrt(iconBits.length);
final int baseSize = getLargeIcon ? 32 : 16;
final BufferedImage img = final BufferedImage img =
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, size, size, iconBits, 0, size); img.setRGB(0, 0, iconSize, iconSize, iconBits, 0, iconSize);
return size == baseSize return img;
? img
: new MultiResolutionIconImage(baseSize, img);
} }
} }
return null; return null;
@ -1043,11 +1051,13 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
public Image getIcon(final boolean getLargeIcon) { public Image getIcon(final boolean getLargeIcon) {
Image icon = getLargeIcon ? largeIcon : smallIcon; Image icon = getLargeIcon ? largeIcon : smallIcon;
int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE;
if (icon == null) { if (icon == null) {
icon = icon =
invoke(new Callable<Image>() { invoke(new Callable<Image>() {
public Image call() { public Image call() {
Image newIcon = null; Image newIcon = null;
Image newIcon2 = null;
if (isLink()) { if (isLink()) {
Win32ShellFolder2 folder = getLinkLocation(false); Win32ShellFolder2 folder = getLinkLocation(false);
if (folder != null && folder.isLibrary()) { if (folder != null && folder.isLibrary()) {
@ -1072,33 +1082,40 @@ final class Win32ShellFolder2 extends ShellFolder {
newIcon = imageCache.get(Integer.valueOf(index)); newIcon = imageCache.get(Integer.valueOf(index));
if (newIcon == null) { if (newIcon == null) {
long hIcon = getIcon(getAbsolutePath(), getLargeIcon); long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
newIcon = makeIcon(hIcon, getLargeIcon); newIcon = makeIcon(hIcon);
disposeIcon(hIcon); disposeIcon(hIcon);
if (newIcon != null) { if (newIcon != null) {
imageCache.put(Integer.valueOf(index), newIcon); imageCache.put(Integer.valueOf(index), newIcon);
} }
} }
if (newIcon != null) {
if (isLink()) {
imageCache = getLargeIcon ? smallLinkedSystemImages
: largeLinkedSystemImages;
} else {
imageCache = getLargeIcon ? smallSystemImages : largeSystemImages;
}
newIcon2 = imageCache.get(index);
if (newIcon2 == null) {
long hIcon = getIcon(getAbsolutePath(), !getLargeIcon);
newIcon2 = makeIcon(hIcon);
disposeIcon(hIcon);
}
}
if (newIcon2 != null) {
Map<Integer, Image> bothIcons = new HashMap<>(2);
bothIcons.put(getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE, newIcon);
bothIcons.put(getLargeIcon ? SMALL_ICON_SIZE : LARGE_ICON_SIZE, newIcon2);
newIcon = new MultiResolutionIconImage(getLargeIcon ? LARGE_ICON_SIZE
: SMALL_ICON_SIZE, bothIcons);
}
} }
} }
if (newIcon == null) { if (hiResIconAvailable(getParentIShellFolder(), getRelativePIDL()) || newIcon == null) {
// These are only cached per object int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE;
long hIcon = extractIcon(getParentIShellFolder(), newIcon = getIcon(size, size);
getRelativePIDL(), getLargeIcon, false);
// E_PENDING: loading can take time so get the default
if(hIcon <= 0) {
hIcon = extractIcon(getParentIShellFolder(),
getRelativePIDL(), getLargeIcon, true);
if(hIcon <= 0) {
if (isDirectory()) {
return getShell32Icon(4, getLargeIcon);
} else {
return getShell32Icon(1, getLargeIcon);
}
}
}
newIcon = makeIcon(hIcon, getLargeIcon);
disposeIcon(hIcon);
} }
if (newIcon == null) { if (newIcon == null) {
@ -1107,21 +1124,68 @@ final class Win32ShellFolder2 extends ShellFolder {
return newIcon; return newIcon;
} }
}); });
if (getLargeIcon) {
largeIcon = icon;
} else {
smallIcon = icon;
}
} }
return icon; return icon;
} }
/**
* @return The icon image of specified size used to display this shell folder
*/
public Image getIcon(int width, int height) {
int size = Math.max(width, height);
return invoke(() -> {
Image newIcon = null;
if (isLink()) {
Win32ShellFolder2 folder = getLinkLocation(false);
if (folder != null && folder.isLibrary()) {
return folder.getIcon(size, size);
}
}
Map<Integer, Image> multiResolutionIcon = new HashMap<>();
int start = size > MAX_QUALITY_ICON ? ICON_RESOLUTIONS.length - 1 : 0;
int increment = size > MAX_QUALITY_ICON ? -1 : 1;
int end = size > MAX_QUALITY_ICON ? -1 : ICON_RESOLUTIONS.length;
for (int i = start; i != end; i += increment) {
int s = ICON_RESOLUTIONS[i];
if (size < MIN_QUALITY_ICON || size > MAX_QUALITY_ICON
|| (s >= size && s <= size*2)) {
long hIcon = extractIcon(getParentIShellFolder(),
getRelativePIDL(), s, false);
// E_PENDING: loading can take time so get the default
if (hIcon <= 0) {
hIcon = extractIcon(getParentIShellFolder(),
getRelativePIDL(), s, true);
if (hIcon <= 0) {
if (isDirectory()) {
return getShell32Icon(FOLDER_ICON_ID, size);
} else {
return getShell32Icon(FILE_ICON_ID, size);
}
}
}
newIcon = makeIcon(hIcon);
disposeIcon(hIcon);
multiResolutionIcon.put(s, newIcon);
if (size < MIN_QUALITY_ICON || size > MAX_QUALITY_ICON) {
break;
}
}
}
return new MultiResolutionIconImage(size, multiResolutionIcon);
});
}
/** /**
* Gets an icon from the Windows system icon list as an {@code Image} * Gets an icon from the Windows system icon list as an {@code Image}
*/ */
static Image getSystemIcon(SystemIcon iconType) { static Image getSystemIcon(SystemIcon iconType) {
long hIcon = getSystemIcon(iconType.getIconID()); long hIcon = getSystemIcon(iconType.getIconID());
Image icon = makeIcon(hIcon, true); Image icon = makeIcon(hIcon);
if (LARGE_ICON_SIZE != icon.getWidth(null)) {
icon = new MultiResolutionIconImage(LARGE_ICON_SIZE, icon);
}
disposeIcon(hIcon); disposeIcon(hIcon);
return icon; return icon;
} }
@ -1129,20 +1193,13 @@ final class Win32ShellFolder2 extends ShellFolder {
/** /**
* Gets an icon from the Windows system icon list as an {@code Image} * Gets an icon from the Windows system icon list as an {@code Image}
*/ */
static Image getShell32Icon(int iconID, boolean getLargeIcon) { static Image getShell32Icon(int iconID, int size) {
boolean useVGAColors = true; // Will be ignored on XP and later long hIcon = getIconResource("shell32.dll", iconID, size, size);
int size = getLargeIcon ? 32 : 16;
Toolkit toolkit = Toolkit.getDefaultToolkit();
String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP");
if (shellIconBPP != null) {
useVGAColors = shellIconBPP.equals("4");
}
long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors);
if (hIcon != 0) { if (hIcon != 0) {
Image icon = makeIcon(hIcon, getLargeIcon); Image icon = makeIcon(hIcon);
if (size != icon.getWidth(null)) {
icon = new MultiResolutionIconImage(size, icon);
}
disposeIcon(hIcon); disposeIcon(hIcon);
return icon; return icon;
} }
@ -1325,13 +1382,17 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
static class MultiResolutionIconImage extends AbstractMultiResolutionImage { static class MultiResolutionIconImage extends AbstractMultiResolutionImage {
final int baseSize; final int baseSize;
final Image resolutionVariant; final Map<Integer, Image> resolutionVariants = new HashMap<>();
public MultiResolutionIconImage(int baseSize, Image resolutionVariant) { public MultiResolutionIconImage(int baseSize, Map<Integer, Image> resolutionVariants) {
this.baseSize = baseSize; this.baseSize = baseSize;
this.resolutionVariant = resolutionVariant; this.resolutionVariants.putAll(resolutionVariants);
}
public MultiResolutionIconImage(int baseSize, Image image) {
this.baseSize = baseSize;
this.resolutionVariants.put(baseSize, image);
} }
@Override @Override
@ -1346,17 +1407,34 @@ final class Win32ShellFolder2 extends ShellFolder {
@Override @Override
protected Image getBaseImage() { protected Image getBaseImage() {
return resolutionVariant; return getResolutionVariant(baseSize, baseSize);
} }
@Override @Override
public Image getResolutionVariant(double width, double height) { public Image getResolutionVariant(double width, double height) {
return resolutionVariant; int dist = 0;
Image retVal = null;
// We only care about width since we don't support non-rectangular icons
int w = (int) width;
int retindex = 0;
for (Integer i : resolutionVariants.keySet()) {
if (retVal == null || dist > Math.abs(i - w)
|| (dist == Math.abs(i - w) && i > retindex)) {
retindex = i;
dist = Math.abs(i - w);
retVal = resolutionVariants.get(i);
if (i == w) {
break;
}
}
}
return retVal;
} }
@Override @Override
public List<Image> getResolutionVariants() { public List<Image> getResolutionVariants() {
return Arrays.asList(resolutionVariant); return Collections.unmodifiableList(
new ArrayList<Image>(resolutionVariants.values()));
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -53,10 +53,12 @@ import sun.util.logging.PlatformLogger;
import static sun.awt.shell.Win32ShellFolder2.DESKTOP; import static sun.awt.shell.Win32ShellFolder2.DESKTOP;
import static sun.awt.shell.Win32ShellFolder2.DRIVES; import static sun.awt.shell.Win32ShellFolder2.DRIVES;
import static sun.awt.shell.Win32ShellFolder2.Invoker; import static sun.awt.shell.Win32ShellFolder2.Invoker;
import static sun.awt.shell.Win32ShellFolder2.LARGE_ICON_SIZE;
import static sun.awt.shell.Win32ShellFolder2.MultiResolutionIconImage; import static sun.awt.shell.Win32ShellFolder2.MultiResolutionIconImage;
import static sun.awt.shell.Win32ShellFolder2.NETWORK; import static sun.awt.shell.Win32ShellFolder2.NETWORK;
import static sun.awt.shell.Win32ShellFolder2.PERSONAL; import static sun.awt.shell.Win32ShellFolder2.PERSONAL;
import static sun.awt.shell.Win32ShellFolder2.RECENT; import static sun.awt.shell.Win32ShellFolder2.RECENT;
import static sun.awt.shell.Win32ShellFolder2.SMALL_ICON_SIZE;
// NOTE: This class supersedes Win32ShellFolderManager, which was removed // NOTE: This class supersedes Win32ShellFolderManager, which was removed
// from distribution after version 1.4.2. // from distribution after version 1.4.2.
@ -144,9 +146,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager {
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, size, size, iconBits, 0, size); img.setRGB(0, 0, size, size, iconBits, 0, size);
STANDARD_VIEW_BUTTONS[iconIndex] = (size == 16) STANDARD_VIEW_BUTTONS[iconIndex] = (size == SMALL_ICON_SIZE)
? img ? img
: new MultiResolutionIconImage(16, img); : new MultiResolutionIconImage(SMALL_ICON_SIZE, img);
} }
return STANDARD_VIEW_BUTTONS[iconIndex]; return STANDARD_VIEW_BUTTONS[iconIndex];
@ -408,7 +410,8 @@ final class Win32ShellFolderManager2 extends ShellFolderManager {
try { try {
int i = Integer.parseInt(name); int i = Integer.parseInt(name);
if (i >= 0) { if (i >= 0) {
return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon ")); return Win32ShellFolder2.getShell32Icon(i,
key.startsWith("shell32LargeIcon ") ? LARGE_ICON_SIZE : SMALL_ICON_SIZE);
} }
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -880,7 +880,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIcon
LPCTSTR pathStr = JNU_GetStringPlatformChars(env, absolutePath, NULL); LPCTSTR pathStr = JNU_GetStringPlatformChars(env, absolutePath, NULL);
JNU_CHECK_EXCEPTION_RETURN(env, 0); JNU_CHECK_EXCEPTION_RETURN(env, 0);
if (fn_SHGetFileInfo(pathStr, 0L, &fileInfo, sizeof(fileInfo), if (fn_SHGetFileInfo(pathStr, 0L, &fileInfo, sizeof(fileInfo),
SHGFI_ICON | (getLargeIcon ? 0 : SHGFI_SMALLICON)) != 0) { SHGFI_ICON | (getLargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON)) != 0) {
hIcon = fileInfo.hIcon; hIcon = fileInfo.hIcon;
} }
JNU_ReleaseStringPlatformChars(env, absolutePath, pathStr); JNU_ReleaseStringPlatformChars(env, absolutePath, pathStr);
@ -912,15 +912,54 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex
return (jint)index; return (jint)index;
} }
/*
* Class: sun.awt.shell.Win32ShellFolder2
* Method: hiResIconAvailable
* Signature: (JJ)Z
*/
JNIEXPORT jboolean JNICALL Java_sun_awt_shell_Win32ShellFolder2_hiResIconAvailable
(JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL)
{
IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
if (pIShellFolder == NULL || pidl == NULL) {
return FALSE;
}
HRESULT hres;
IExtractIconW* pIcon;
hres = pIShellFolder->GetUIObjectOf(NULL, 1, const_cast<LPCITEMIDLIST*>(&pidl),
IID_IExtractIconW, NULL, (void**)&pIcon);
if (SUCCEEDED(hres)) {
WCHAR szBuf[MAX_PATH];
INT index;
UINT flags;
UINT uFlags = GIL_FORSHELL | GIL_ASYNC;
hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
if (SUCCEEDED(hres)) {
pIcon->Release();
return wcscmp(szBuf, L"*") != 0;
} else if (hres == E_PENDING) {
uFlags = GIL_DEFAULTICON;
hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
if (SUCCEEDED(hres)) {
pIcon->Release();
return wcscmp(szBuf, L"*") != 0;
}
}
pIcon->Release();
}
return FALSE;
}
/* /*
* Class: sun_awt_shell_Win32ShellFolder2 * Class: sun_awt_shell_Win32ShellFolder2
* Method: extractIcon * Method: extractIcon
* Signature: (JJZZ)J * Signature: (JJIZ)J
*/ */
JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
(JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL, (JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL,
jboolean getLargeIcon, jboolean getDefaultIcon) jint size, jboolean getDefaultIcon)
{ {
IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL; IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL; LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
@ -941,16 +980,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
UINT uFlags = getDefaultIcon ? GIL_DEFAULTICON : GIL_FORSHELL | GIL_ASYNC; UINT uFlags = getDefaultIcon ? GIL_DEFAULTICON : GIL_FORSHELL | GIL_ASYNC;
hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags); hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
if (SUCCEEDED(hres)) { if (SUCCEEDED(hres)) {
HICON hIconLarge; if (size < 24) {
hres = pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32); size = 16;
if (SUCCEEDED(hres)) {
if (getLargeIcon) {
fn_DestroyIcon((HICON)hIcon);
hIcon = hIconLarge;
} else {
fn_DestroyIcon((HICON)hIconLarge);
}
} }
hres = pIcon->Extract(szBuf, index, &hIcon, NULL, size);
} else if (hres == E_PENDING) { } else if (hres == E_PENDING) {
pIcon->Release(); pIcon->Release();
return E_PENDING; return E_PENDING;
@ -980,7 +1013,7 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_disposeIcon
JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
(JNIEnv* env, jclass cls, jlong hicon) (JNIEnv* env, jclass cls, jlong hicon)
{ {
const int MAX_ICON_SIZE = 128; const int MAX_ICON_SIZE = 256;
int iconSize = 0; int iconSize = 0;
jintArray iconBits = NULL; jintArray iconBits = NULL;
@ -1121,11 +1154,11 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getSystemIcon
/* /*
* Class: sun_awt_shell_Win32ShellFolder2 * Class: sun_awt_shell_Win32ShellFolder2
* Method: getIconResource * Method: getIconResource
* Signature: (Ljava/lang/String;IIIZ)J * Signature: (Ljava/lang/String;III)J
*/ */
JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource
(JNIEnv* env, jclass cls, jstring libName, jint iconID, (JNIEnv* env, jclass cls, jstring libName, jint iconID,
jint cxDesired, jint cyDesired, jboolean useVGAColors) jint cxDesired, jint cyDesired)
{ {
const char *pLibName = env->GetStringUTFChars(libName, NULL); const char *pLibName = env->GetStringUTFChars(libName, NULL);
JNU_CHECK_EXCEPTION_RETURN(env, 0); JNU_CHECK_EXCEPTION_RETURN(env, 0);
@ -1134,10 +1167,9 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource
env->ReleaseStringUTFChars(libName, pLibName); env->ReleaseStringUTFChars(libName, pLibName);
} }
if (libHandle != NULL) { if (libHandle != NULL) {
UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0;
return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID), return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID),
IMAGE_ICON, cxDesired, cyDesired, IMAGE_ICON, cxDesired, cyDesired,
fuLoad)); 0));
} }
return 0; return 0;
} }

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8182043
* @summary Access to Windows Large Icons
* @run main SystemIconTest
*/
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import java.awt.image.MultiResolutionImage;
import java.io.File;
public class SystemIconTest {
static final FileSystemView fsv = FileSystemView.getFileSystemView();
public static void main(String[] args) {
testSystemIcon();
negativeTests();
}
static void testSystemIcon() {
String os = System.getProperty("os.name");
if (os.startsWith("Windows")) {
String windir = System.getenv("windir");
testSystemIcon(new File(windir), true);
testSystemIcon(new File(windir + "/explorer.exe"),
true);
} else {
String homedir = System.getProperty("user.home");
testSystemIcon(new File(homedir), false);
}
}
static void negativeTests() {
Icon icon;
try {
icon = fsv.getSystemIcon(new File("."), -1, 16);
throw new RuntimeException("Negative size icon should throw invalid argument exception");
} catch (IllegalArgumentException iae) {
// Expected
}
icon = fsv.getSystemIcon(new File("thereisdefinitelynosuchfile.why"),
16, 16);
if (icon != null) {
throw new RuntimeException("Icons for files with invalid names should be null");
}
}
static void testSystemIcon(File file, boolean implComplete) {
int[] sizes = new int[] {16, 32, 48, 64, 128};
for (int size : sizes) {
ImageIcon icon = (ImageIcon) fsv.getSystemIcon(file, size, size);
//Enable below to see the icon
//JLabel label = new JLabel(icon);
//JOptionPane.showMessageDialog(null, label);
if (icon == null) {
throw new RuntimeException("icon is null!!!");
}
if (implComplete && icon.getIconWidth() != size) {
throw new RuntimeException("Wrong icon size " +
icon.getIconWidth() + " when requested " + size);
}
if (icon.getImage() instanceof MultiResolutionImage) {
MultiResolutionImage mri = (MultiResolutionImage) icon.getImage();
if (mri.getResolutionVariant(size, size) == null) {
throw new RuntimeException("There is no suitable variant for the size "
+ size + " in the multi resolution icon");
}
} else {
if (implComplete) {
throw new RuntimeException("icon is supposed to be multi-resolution but it is not");
}
}
}
}
}