diff --git a/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java index 8cff0a3e7cb4accf6153592881333ef874e23082..b823553b627172769771cb72b7b6b6ee0c777547 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -27,6 +27,7 @@ package javax.swing.plaf.basic; import java.io.File; import java.util.*; +import java.util.concurrent.Callable; import javax.swing.*; import javax.swing.filechooser.*; import javax.swing.event.*; @@ -223,113 +224,115 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh this.fid = fid; } - private void invokeLater(DoChangeContents runnable) { - runnables.addElement(runnable); - SwingUtilities.invokeLater(runnable); - } - public void run() { run0(); setBusy(false, fid); } public void run0() { - FileSystemView fileSystem = filechooser.getFileSystemView(); + DoChangeContents doChangeContents = ShellFolder.getInvoker().invoke(new Callable() { + public DoChangeContents call() throws Exception { + FileSystemView fileSystem = filechooser.getFileSystemView(); - File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); + File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); - Vector acceptsList = new Vector(); + Vector acceptsList = new Vector(); - if (isInterrupted()) { - return; - } + if (isInterrupted()) { + return null; + } - // run through the file list, add directories and selectable files to fileCache - for (File file : list) { - if (filechooser.accept(file)) { - acceptsList.addElement(file); - } - } + // run through the file list, add directories and selectable files to fileCache + for (File file : list) { + if (filechooser.accept(file)) { + acceptsList.addElement(file); + } + } - if (isInterrupted()) { - return; - } + if (isInterrupted()) { + return null; + } - // First sort alphabetically by filename - sort(acceptsList); - - Vector newDirectories = new Vector(50); - Vector newFiles = new Vector(); - // run through list grabbing directories in chunks of ten - for(int i = 0; i < acceptsList.size(); i++) { - File f = acceptsList.elementAt(i); - boolean isTraversable = filechooser.isTraversable(f); - if (isTraversable) { - newDirectories.addElement(f); - } else if (!isTraversable && filechooser.isFileSelectionEnabled()) { - newFiles.addElement(f); - } - if(isInterrupted()) { - return; - } - } + // First sort alphabetically by filename + sort(acceptsList); + + Vector newDirectories = new Vector(50); + Vector newFiles = new Vector(); + // run through list grabbing directories in chunks of ten + for (int i = 0; i < acceptsList.size(); i++) { + File f = acceptsList.elementAt(i); + boolean isTraversable = filechooser.isTraversable(f); + if (isTraversable) { + newDirectories.addElement(f); + } else if (!isTraversable && filechooser.isFileSelectionEnabled()) { + newFiles.addElement(f); + } + if (isInterrupted()) { + return null; + } + } - Vector newFileCache = new Vector(newDirectories); - newFileCache.addAll(newFiles); - - int newSize = newFileCache.size(); - int oldSize = fileCache.size(); - - if (newSize > oldSize) { - //see if interval is added - int start = oldSize; - int end = newSize; - for (int i = 0; i < oldSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - for (int j = i; j < newSize; j++) { - if (newFileCache.get(j).equals(fileCache.get(i))) { - end = j; + Vector newFileCache = new Vector(newDirectories); + newFileCache.addAll(newFiles); + + int newSize = newFileCache.size(); + int oldSize = fileCache.size(); + + if (newSize > oldSize) { + //see if interval is added + int start = oldSize; + int end = newSize; + for (int i = 0; i < oldSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + for (int j = i; j < newSize; j++) { + if (newFileCache.get(j).equals(fileCache.get(i))) { + end = j; + break; + } + } break; } } - break; - } - } - if (start >= 0 && end > start - && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) { - if(isInterrupted()) { - return; - } - invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid)); - newFileCache = null; - } - } else if (newSize < oldSize) { - //see if interval is removed - int start = -1; - int end = -1; - for (int i = 0; i < newSize; i++) { - if (!newFileCache.get(i).equals(fileCache.get(i))) { - start = i; - end = i + oldSize - newSize; - break; + if (start >= 0 && end > start + && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) { + if (isInterrupted()) { + return null; + } + return new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid); + } + } else if (newSize < oldSize) { + //see if interval is removed + int start = -1; + int end = -1; + for (int i = 0; i < newSize; i++) { + if (!newFileCache.get(i).equals(fileCache.get(i))) { + start = i; + end = i + oldSize - newSize; + break; + } + } + if (start >= 0 && end > start + && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) { + if (isInterrupted()) { + return null; + } + return new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), start, fid); + } } - } - if (start >= 0 && end > start - && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) { - if(isInterrupted()) { - return; + if (!fileCache.equals(newFileCache)) { + if (isInterrupted()) { + cancelRunnables(runnables); + } + return new DoChangeContents(newFileCache, 0, fileCache, 0, fid); } - invokeLater(new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), - start, fid)); - newFileCache = null; - } - } - if (newFileCache != null && !fileCache.equals(newFileCache)) { - if (isInterrupted()) { - cancelRunnables(runnables); + return null; } - invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid)); + }); + + if (doChangeContents != null) { + runnables.addElement(doChangeContents); + SwingUtilities.invokeLater(doChangeContents); } } diff --git a/src/share/classes/sun/awt/shell/ShellFolder.java b/src/share/classes/sun/awt/shell/ShellFolder.java index 16c1b12cb80ef6e3ce5a5f1355322d93a24b4009..0e75ac183dcfa8eefea46171691abadc3fe7098c 100644 --- a/src/share/classes/sun/awt/shell/ShellFolder.java +++ b/src/share/classes/sun/awt/shell/ShellFolder.java @@ -31,6 +31,7 @@ import java.awt.Toolkit; import java.io.*; import java.io.FileNotFoundException; import java.util.*; +import java.util.concurrent.Callable; /** * @author Michael Martak @@ -461,6 +462,35 @@ public abstract class ShellFolder extends File { return null; } + private static Invoker invoker; + + /** + * Provides the single access point to the {@link Invoker}. It is guaranteed that the value + * returned by this method will be always the same. + * + * @return the singleton instance of {@link Invoker} + */ + public static Invoker getInvoker() { + if (invoker == null) { + invoker = shellFolderManager.createInvoker(); + } + return invoker; + } + + /** + * Interface allowing to invoke tasks in different environments on different platforms. + */ + public static interface Invoker { + /** + * Invokes a callable task. If the {@code task} throws a checked exception, + * it will be wrapped into a {@link RuntimeException} + * + * @param task a task to invoke + * @return the result of {@code task}'s invokation + */ + T invoke(Callable task); + } + /** * Provides a default comparator for the default column set */ diff --git a/src/share/classes/sun/awt/shell/ShellFolderManager.java b/src/share/classes/sun/awt/shell/ShellFolderManager.java index 8fb15bf0cf8c39b48310d92155cdc5ebe0006811..dc8901f7bc5aebc4fb185d661b0c4bd40a06d118 100644 --- a/src/share/classes/sun/awt/shell/ShellFolderManager.java +++ b/src/share/classes/sun/awt/shell/ShellFolderManager.java @@ -27,6 +27,7 @@ package sun.awt.shell; import java.io.File; import java.io.FileNotFoundException; +import java.util.concurrent.Callable; /** * @author Michael Martak @@ -96,9 +97,23 @@ class ShellFolderManager { } public boolean isFileSystemRoot(File dir) { - if (dir instanceof ShellFolder && !((ShellFolder)dir).isFileSystem()) { + if (dir instanceof ShellFolder && !((ShellFolder) dir).isFileSystem()) { return false; } return (dir.getParentFile() == null); } + + protected ShellFolder.Invoker createInvoker() { + return new DirectInvoker(); + } + + private static class DirectInvoker implements ShellFolder.Invoker { + public T invoke(Callable task) { + try { + return task.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } } diff --git a/src/share/classes/sun/swing/FilePane.java b/src/share/classes/sun/swing/FilePane.java index de5ad7c48312a90b45128ba55df1eadfdb1f4956..71112b319d8c328c91236bc719ce0a0638565faa 100644 --- a/src/share/classes/sun/swing/FilePane.java +++ b/src/share/classes/sun/swing/FilePane.java @@ -34,6 +34,7 @@ import java.text.DateFormat; import java.text.MessageFormat; import java.util.*; import java.util.List; +import java.util.concurrent.Callable; import javax.swing.*; import javax.swing.border.*; @@ -900,6 +901,16 @@ public class FilePane extends JPanel implements PropertyChangeListener { } } + @Override + public void sort() { + ShellFolder.getInvoker().invoke(new Callable() { + public Void call() throws Exception { + DetailsTableRowSorter.super.sort(); + return null; + } + }); + } + public void modelStructureChanged() { super.modelStructureChanged(); updateComparators(detailsTableModel.getColumns()); diff --git a/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java index 418dc8f59dbb83417600c6f6ff5a1702d2beeb11..bc81b80e7931e85842640bb1965f25cd4d454a40 100644 --- a/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; +import java.util.concurrent.*; import javax.swing.SwingConstants; // NOTE: This class supersedes Win32ShellFolder, which was removed from @@ -184,15 +185,20 @@ final class Win32ShellFolder2 extends ShellFolder { boolean disposed; public void dispose() { if (disposed) return; - if (relativePIDL != 0) { - releasePIDL(relativePIDL); - } - if (absolutePIDL != 0) { - releasePIDL(absolutePIDL); - } - if (pIShellFolder != 0) { - releaseIShellFolder(pIShellFolder); - } + ShellFolder.getInvoker().invoke(new Callable() { + public Void call() throws Exception { + if (relativePIDL != 0) { + releasePIDL(relativePIDL); + } + if (absolutePIDL != 0) { + releasePIDL(absolutePIDL); + } + if (pIShellFolder != 0) { + releaseIShellFolder(pIShellFolder); + } + return null; + } + }); disposed = true; } } @@ -218,50 +224,59 @@ final class Win32ShellFolder2 extends ShellFolder { */ private boolean isPersonal; + private static String composePathForCsidl(int csidl) throws IOException { + String path = getFileSystemPath(csidl); + return path == null + ? ("ShellFolder: 0x" + Integer.toHexString(csidl)) + : path; + } /** * Create a system special shell folder, such as the * desktop or Network Neighborhood. */ - Win32ShellFolder2(int csidl) throws IOException { + Win32ShellFolder2(final int csidl) throws IOException { // Desktop is parent of DRIVES and NETWORK, not necessarily // other special shell folders. - super(null, - (getFileSystemPath(csidl) == null) - ? ("ShellFolder: 0x"+Integer.toHexString(csidl)) : getFileSystemPath(csidl)); - if (csidl == DESKTOP) { - initDesktop(); - } else { - initSpecial(getDesktop().getIShellFolder(), csidl); - // At this point, the native method initSpecial() has set our relativePIDL - // relative to the Desktop, which may not be our immediate parent. We need - // to traverse this ID list and break it into a chain of shell folders from - // the top, with each one having an immediate parent and a relativePIDL - // relative to that parent. - long pIDL = disposer.relativePIDL; - parent = getDesktop(); - while (pIDL != 0) { - // Get a child pidl relative to 'parent' - long childPIDL = copyFirstPIDLEntry(pIDL); - if (childPIDL != 0) { - // Get a handle to the the rest of the ID list - // i,e, parent's grandchilren and down - pIDL = getNextPIDLEntry(pIDL); - if (pIDL != 0) { - // Now we know that parent isn't immediate to 'this' because it - // has a continued ID list. Create a shell folder for this child - // pidl and make it the new 'parent'. - parent = new Win32ShellFolder2((Win32ShellFolder2)parent, childPIDL); - } else { - // No grandchildren means we have arrived at the parent of 'this', - // and childPIDL is directly relative to parent. - disposer.relativePIDL = childPIDL; - } + super(null, composePathForCsidl(csidl)); + ShellFolder.getInvoker().invoke(new Callable() { + public Void call() throws Exception { + if (csidl == DESKTOP) { + initDesktop(); } else { - break; + initSpecial(getDesktop().getIShellFolder(), csidl); + // At this point, the native method initSpecial() has set our relativePIDL + // relative to the Desktop, which may not be our immediate parent. We need + // to traverse this ID list and break it into a chain of shell folders from + // the top, with each one having an immediate parent and a relativePIDL + // relative to that parent. + long pIDL = disposer.relativePIDL; + parent = getDesktop(); + while (pIDL != 0) { + // Get a child pidl relative to 'parent' + long childPIDL = copyFirstPIDLEntry(pIDL); + if (childPIDL != 0) { + // Get a handle to the the rest of the ID list + // i,e, parent's grandchilren and down + pIDL = getNextPIDLEntry(pIDL); + if (pIDL != 0) { + // Now we know that parent isn't immediate to 'this' because it + // has a continued ID list. Create a shell folder for this child + // pidl and make it the new 'parent'. + parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL); + } else { + // No grandchildren means we have arrived at the parent of 'this', + // and childPIDL is directly relative to parent. + disposer.relativePIDL = childPIDL; + } + } else { + break; + } + } } + return null; } - } + }); sun.java2d.Disposer.addRecord(this, disposer); } @@ -281,17 +296,26 @@ final class Win32ShellFolder2 extends ShellFolder { /** * Creates a shell folder with a parent and relative PIDL */ - Win32ShellFolder2(Win32ShellFolder2 parent, long relativePIDL) { - super(parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL)); + Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) { + super(parent, + ShellFolder.getInvoker().invoke(new Callable() { + public String call() throws Exception { + return getFileSystemPath(parent.getIShellFolder(), relativePIDL); + } + }) + ); this.disposer.relativePIDL = relativePIDL; getAbsolutePath(); sun.java2d.Disposer.addRecord(this, disposer); } // Initializes the desktop shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void initDesktop(); + // Initializes a special, non-file system shell folder // from one of the above constants + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void initSpecial(long desktopIShellFolder, int csidl); /** Marks this folder as being the My Documents (Personal) folder */ @@ -311,26 +335,30 @@ final class Win32ShellFolder2 extends ShellFolder { * drive (normally "C:\"). */ protected Object writeReplace() throws java.io.ObjectStreamException { - if (isFileSystem()) { - return new File(getPath()); - } else { - Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives(); - if (drives != null) { - File[] driveRoots = drives.listFiles(); - if (driveRoots != null) { - for (int i = 0; i < driveRoots.length; i++) { - if (driveRoots[i] instanceof Win32ShellFolder2) { - Win32ShellFolder2 sf = (Win32ShellFolder2)driveRoots[i]; - if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) { - return new File(sf.getPath()); + return ShellFolder.getInvoker().invoke(new Callable() { + public File call() throws Exception { + if (isFileSystem()) { + return new File(getPath()); + } else { + Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives(); + if (drives != null) { + File[] driveRoots = drives.listFiles(); + if (driveRoots != null) { + for (int i = 0; i < driveRoots.length; i++) { + if (driveRoots[i] instanceof Win32ShellFolder2) { + Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i]; + if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) { + return new File(sf.getPath()); + } + } } } } + // Ouch, we have no hard drives. Return something "valid" anyway. + return new File("C:\\"); } } - // Ouch, we have no hard drives. Return something "valid" anyway. - return new File("C:\\"); - } + }); } @@ -364,6 +392,7 @@ final class Win32ShellFolder2 extends ShellFolder { static native void releasePIDL(long pIDL); // Release an IShellFolder object + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native void releaseIShellFolder(long pIShellFolder); /** @@ -371,18 +400,28 @@ final class Win32ShellFolder2 extends ShellFolder { */ public long getIShellFolder() { if (disposer.pIShellFolder == 0) { - assert(isDirectory()); - assert(parent != null); - long parentIShellFolder = getParentIShellFolder(); - if (parentIShellFolder == 0) { - throw new InternalError("Parent IShellFolder was null for " + getAbsolutePath()); - } - // We are a directory with a parent and a relative PIDL. - // We want to bind to the parent so we get an IShellFolder instance associated with us. - disposer.pIShellFolder = bindToObject(parentIShellFolder, disposer.relativePIDL); - if (disposer.pIShellFolder == 0) { - throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent"); - } + disposer.pIShellFolder = + ShellFolder.getInvoker().invoke(new Callable() { + public Long call() throws Exception { + assert(isDirectory()); + assert(parent != null); + long parentIShellFolder = getParentIShellFolder(); + if (parentIShellFolder == 0) { + throw new InternalError("Parent IShellFolder was null for " + + getAbsolutePath()); + } + // We are a directory with a parent and a relative PIDL. + // We want to bind to the parent so we get an + // IShellFolder instance associated with us. + long pIShellFolder = bindToObject(parentIShellFolder, + disposer.relativePIDL); + if (pIShellFolder == 0) { + throw new InternalError("Unable to bind " + + getAbsolutePath() + " to parent"); + } + return pIShellFolder; + } + }); } return disposer.pIShellFolder; } @@ -472,24 +511,42 @@ final class Win32ShellFolder2 extends ShellFolder { return false; } - private static boolean pidlsEqual(long pIShellFolder, long pidl1, long pidl2) { - return (compareIDs(pIShellFolder, pidl1, pidl2) == 0); + private static boolean pidlsEqual(final long pIShellFolder, final long pidl1, final long pidl2) { + return ShellFolder.getInvoker().invoke(new Callable() { + public Boolean call() throws Exception { + return (compareIDs(pIShellFolder, pidl1, pidl2) == 0); + } + }); } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2); + private Boolean cachedIsFileSystem; + /** * @return Whether this is a file system shell folder */ - public boolean isFileSystem() { - return hasAttribute(ATTRIB_FILESYSTEM); + public synchronized boolean isFileSystem() { + if (cachedIsFileSystem == null) { + cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM); + } + + return cachedIsFileSystem; } /** * Return whether the given attribute flag is set for this object */ - public boolean hasAttribute(int attribute) { - // Caching at this point doesn't seem to be cost efficient - return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0; + public boolean hasAttribute(final int attribute) { + return ShellFolder.getInvoker().invoke(new Callable() { + public Boolean call() throws Exception { + // Caching at this point doesn't seem to be cost efficient + return (getAttributes0(getParentIShellFolder(), + getRelativePIDL(), attribute) + & attribute) != 0; + } + }); } /** @@ -498,26 +555,42 @@ final class Win32ShellFolder2 extends ShellFolder { * Could plausibly be used for attribute caching but have to be * very careful not to touch network drives and file system roots * with a full attrsMask + * NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details */ + private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask); // Return the path to the underlying file system object - private static String getFileSystemPath(long parentIShellFolder, long relativePIDL) { - int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER; - if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() && - getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) { - - String s = - getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(), - getLinkLocation(parentIShellFolder, relativePIDL, false)); - if (s != null && s.startsWith("\\\\")) { - return s; + private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) { + return ShellFolder.getInvoker().invoke(new Callable() { + public String call() throws Exception { + int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER; + if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() && + getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) { + + String s = + getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(), + getLinkLocation(parentIShellFolder, relativePIDL, false)); + if (s != null && s.startsWith("\\\\")) { + return s; + } + } + return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING); } - } - return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING); + }); } + // Needs to be accessible to Win32ShellFolderManager2 - static native String getFileSystemPath(int csidl) throws IOException; + static String getFileSystemPath(final int csidl) throws IOException { + return ShellFolder.getInvoker().invoke(new Callable() { + public String call() throws Exception { + return getFileSystemPath0(csidl); + } + }); + } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details + private static native String getFileSystemPath0(int csidl) throws IOException; // Return whether the path is a network root. // Path is assumed to be non-null @@ -557,24 +630,33 @@ final class Win32ShellFolder2 extends ShellFolder { */ // Returns an IEnumIDList interface for an IShellFolder. The value // returned must be released using releaseEnumObjects(). - private long getEnumObjects(long pIShellFolder, boolean includeHiddenFiles) { - boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder()); - return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles); + private long getEnumObjects(long pIShellFolder, final boolean includeHiddenFiles) { + final boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder()); + return ShellFolder.getInvoker().invoke(new Callable() { + public Long call() throws Exception { + return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles); + } + }); } + // Returns an IEnumIDList interface for an IShellFolder. The value // returned must be released using releaseEnumObjects(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native long getEnumObjects(long pIShellFolder, boolean isDesktop, boolean includeHiddenFiles); // Returns the next sequential child as a relative PIDL // from an IEnumIDList interface. The value returned must // be released using releasePIDL(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native long getNextChild(long pEnumObjects); // Releases the IEnumIDList interface + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native void releaseEnumObjects(long pEnumObjects); // Returns the IShellFolder of a child from a parent IShellFolder // and a relative PIDL. The value returned must be released // using releaseIShellFolder(). + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long bindToObject(long parentIShellFolder, long pIDL); /** @@ -582,60 +664,64 @@ final class Win32ShellFolder2 extends ShellFolder { * object. The array will be empty if the folder is empty. Returns * null if this shellfolder does not denote a directory. */ - public File[] listFiles(boolean includeHiddenFiles) { + public File[] listFiles(final boolean includeHiddenFiles) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(getPath()); } - if (!isDirectory()) { - return null; - } - // Links to directories are not directories and cannot be parents. - // This does not apply to folders in My Network Places (NetHood) - // because they are both links and real directories! - if (isLink() && !hasAttribute(ATTRIB_FOLDER)) { - return new File[0]; - } - Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop(); - Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal(); - - // If we are a directory, we have a parent and (at least) a - // relative PIDL. We must first ensure we are bound to the - // parent so we have an IShellFolder to query. - long pIShellFolder = getIShellFolder(); - // Now we can enumerate the objects in this folder. - ArrayList list = new ArrayList(); - long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles); - if (pEnumObjects != 0) { - long childPIDL; - int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; - do { - if (Thread.currentThread().isInterrupted()) { - return new File[0]; + return ShellFolder.getInvoker().invoke(new Callable() { + public File[] call() throws Exception { + if (!isDirectory()) { + return null; } - childPIDL = getNextChild(pEnumObjects); - boolean releasePIDL = true; - if (childPIDL != 0 && - (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { - Win32ShellFolder2 childFolder = null; - if (this.equals(desktop) - && personal != null - && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { - childFolder = personal; - } else { - childFolder = new Win32ShellFolder2(this, childPIDL); - releasePIDL = false; - } - list.add(childFolder); + // Links to directories are not directories and cannot be parents. + // This does not apply to folders in My Network Places (NetHood) + // because they are both links and real directories! + if (isLink() && !hasAttribute(ATTRIB_FOLDER)) { + return new File[0]; } - if (releasePIDL) { - releasePIDL(childPIDL); + + Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop(); + Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal(); + + // If we are a directory, we have a parent and (at least) a + // relative PIDL. We must first ensure we are bound to the + // parent so we have an IShellFolder to query. + long pIShellFolder = getIShellFolder(); + // Now we can enumerate the objects in this folder. + ArrayList list = new ArrayList(); + long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles); + if (pEnumObjects != 0) { + long childPIDL; + int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; + do { + childPIDL = getNextChild(pEnumObjects); + boolean releasePIDL = true; + if (childPIDL != 0 && + (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { + Win32ShellFolder2 childFolder; + if (Win32ShellFolder2.this.equals(desktop) + && personal != null + && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { + childFolder = personal; + } else { + childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL); + releasePIDL = false; + } + list.add(childFolder); + } + if (releasePIDL) { + releasePIDL(childPIDL); + } + } while (childPIDL != 0 && !Thread.currentThread().isInterrupted()); + releaseEnumObjects(pEnumObjects); } - } while (childPIDL != 0); - releaseEnumObjects(pEnumObjects); - } - return list.toArray(new ShellFolder[list.size()]); + return Thread.currentThread().isInterrupted() + ? new File[0] + : list.toArray(new ShellFolder[list.size()]); + } + }); } @@ -644,33 +730,43 @@ final class Win32ShellFolder2 extends ShellFolder { * * @return The child shellfolder, or null if not found. */ - Win32ShellFolder2 getChildByPath(String filePath) { - long pIShellFolder = getIShellFolder(); - long pEnumObjects = getEnumObjects(pIShellFolder, true); - Win32ShellFolder2 child = null; - long childPIDL; - - while ((childPIDL = getNextChild(pEnumObjects)) != 0) { - if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) { - String path = getFileSystemPath(pIShellFolder, childPIDL); - if (path != null && path.equalsIgnoreCase(filePath)) { - long childIShellFolder = bindToObject(pIShellFolder, childPIDL); - child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path); - break; + Win32ShellFolder2 getChildByPath(final String filePath) { + return ShellFolder.getInvoker().invoke(new Callable() { + public Win32ShellFolder2 call() throws Exception { + long pIShellFolder = getIShellFolder(); + long pEnumObjects = getEnumObjects(pIShellFolder, true); + Win32ShellFolder2 child = null; + long childPIDL = 0; + + while ((childPIDL = getNextChild(pEnumObjects)) != 0) { + if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) { + String path = getFileSystemPath(pIShellFolder, childPIDL); + if (path != null && path.equalsIgnoreCase(filePath)) { + long childIShellFolder = bindToObject(pIShellFolder, childPIDL); + child = new Win32ShellFolder2(Win32ShellFolder2.this, + childIShellFolder, childPIDL, path); + break; + } + } + releasePIDL(childPIDL); } + releaseEnumObjects(pEnumObjects); + return child; } - releasePIDL(childPIDL); - } - releaseEnumObjects(pEnumObjects); - return child; + }); } + private Boolean cachedIsLink; /** * @return Whether this shell folder is a link */ - public boolean isLink() { - return hasAttribute(ATTRIB_LINK); + public synchronized boolean isLink() { + if (cachedIsLink == null) { + cachedIsLink = hasAttribute(ATTRIB_LINK); + } + + return cachedIsLink; } /** @@ -682,6 +778,7 @@ final class Win32ShellFolder2 extends ShellFolder { // Return the link location of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long getLinkLocation(long parentIShellFolder, long relativePIDL, boolean resolve); @@ -693,38 +790,52 @@ final class Win32ShellFolder2 extends ShellFolder { return getLinkLocation(true); } - private ShellFolder getLinkLocation(boolean resolve) { - if (!isLink()) { - return null; - } + private ShellFolder getLinkLocation(final boolean resolve) { + return ShellFolder.getInvoker().invoke(new Callable() { + public ShellFolder call() throws Exception { + if (!isLink()) { + return null; + } - ShellFolder location = null; - long linkLocationPIDL = getLinkLocation(getParentIShellFolder(), - getRelativePIDL(), resolve); - if (linkLocationPIDL != 0) { - try { - location = - Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(), - linkLocationPIDL); - } catch (InternalError e) { - // Could be a link to a non-bindable object, such as a network connection - // TODO: getIShellFolder() should throw FileNotFoundException instead + ShellFolder location = null; + long linkLocationPIDL = getLinkLocation(getParentIShellFolder(), + getRelativePIDL(), resolve); + if (linkLocationPIDL != 0) { + try { + location = + Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(), + linkLocationPIDL); + } catch (InternalError e) { + // Could be a link to a non-bindable object, such as a network connection + // TODO: getIShellFolder() should throw FileNotFoundException instead + } + } + return location; } - } - return location; + }); } // Parse a display name into a PIDL relative to the current IShellFolder. - long parseDisplayName(String name) throws FileNotFoundException { + long parseDisplayName(final String name) throws FileNotFoundException { try { - return parseDisplayName0(getIShellFolder(), name); - } catch (IOException e) { - throw new FileNotFoundException("Could not find file " + name); + return ShellFolder.getInvoker().invoke(new Callable() { + public Long call() throws Exception { + return parseDisplayName0(getIShellFolder(), name); + } + }); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + throw new FileNotFoundException("Could not find file " + name); + } + throw e; } } + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long parseDisplayName0(long pIShellFolder, String name) throws IOException; // Return the display name of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native String getDisplayNameOf(long parentIShellFolder, long relativePIDL, int attrs); @@ -734,12 +845,19 @@ final class Win32ShellFolder2 extends ShellFolder { */ public String getDisplayName() { if (displayName == null) { - displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL); + displayName = + ShellFolder.getInvoker().invoke(new Callable() { + public String call() throws Exception { + return getDisplayNameOf(getParentIShellFolder(), + getRelativePIDL(), SHGDN_NORMAL); + } + }); } return displayName; } // Return the folder type of a shell folder + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native String getFolderType(long pIDL); /** @@ -747,7 +865,13 @@ final class Win32ShellFolder2 extends ShellFolder { */ public String getFolderType() { if (folderType == null) { - folderType = getFolderType(getAbsolutePIDL()); + final long absolutePIDL = getAbsolutePIDL(); + folderType = + ShellFolder.getInvoker().invoke(new Callable() { + public String call() throws Exception { + return getFolderType(absolutePIDL); + } + }); } return folderType; } @@ -774,11 +898,16 @@ final class Win32ShellFolder2 extends ShellFolder { private static Map smallLinkedSystemImages = new HashMap(); private static Map largeLinkedSystemImages = new HashMap(); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native long getIShellIcon(long pIShellFolder); + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int getIconIndex(long parentIShellIcon, long relativePIDL); // Return the icon of a file system shell folder in the form of an HICON private static native long getIcon(String absolutePath, boolean getLargeIcon); + + // 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, boolean getLargeIcon); @@ -799,7 +928,12 @@ final class Win32ShellFolder2 extends ShellFolder { private long getIShellIcon() { if (pIShellIcon == -1L) { - pIShellIcon = getIShellIcon(getIShellFolder()); + pIShellIcon = + ShellFolder.getInvoker().invoke(new Callable() { + public Long call() throws Exception { + return getIShellIcon(getIShellFolder()); + } + }); } return pIShellIcon; } @@ -850,50 +984,60 @@ final class Win32ShellFolder2 extends ShellFolder { /** * @return The icon image used to display this shell folder */ - public Image getIcon(boolean getLargeIcon) { + public Image getIcon(final boolean getLargeIcon) { Image icon = getLargeIcon ? largeIcon : smallIcon; if (icon == null) { - long parentIShellIcon = (parent != null) ? ((Win32ShellFolder2)parent).getIShellIcon() : 0L; - long relativePIDL = getRelativePIDL(); - - if (isFileSystem()) { - // These are cached per type (using the index in the system image list) - int index = getIconIndex(parentIShellIcon, relativePIDL); - if (index > 0) { - Map imageCache; - if (isLink()) { - imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; - } else { - imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; - } - icon = (Image)imageCache.get(Integer.valueOf(index)); - if (icon == null) { - long hIcon = getIcon(getAbsolutePath(), getLargeIcon); - icon = makeIcon(hIcon, getLargeIcon); - disposeIcon(hIcon); - if (icon != null) { - imageCache.put(Integer.valueOf(index), icon); + icon = + ShellFolder.getInvoker().invoke(new Callable() { + public Image call() throws Exception { + Image newIcon = null; + if (isFileSystem()) { + long parentIShellIcon = (parent != null) + ? ((Win32ShellFolder2) parent).getIShellIcon() + : 0L; + long relativePIDL = getRelativePIDL(); + + // These are cached per type (using the index in the system image list) + int index = getIconIndex(parentIShellIcon, relativePIDL); + if (index > 0) { + Map imageCache; + if (isLink()) { + imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages; + } else { + imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; + } + newIcon = (Image) imageCache.get(Integer.valueOf(index)); + if (newIcon == null) { + long hIcon = getIcon(getAbsolutePath(), getLargeIcon); + newIcon = makeIcon(hIcon, getLargeIcon); + disposeIcon(hIcon); + if (newIcon != null) { + imageCache.put(Integer.valueOf(index), newIcon); + } + } + } } - } - } - } - if (icon == null) { - // These are only cached per object - long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon); - icon = makeIcon(hIcon, getLargeIcon); - disposeIcon(hIcon); - } + if (newIcon == null) { + // These are only cached per object + long hIcon = extractIcon(getParentIShellFolder(), + getRelativePIDL(), getLargeIcon); + newIcon = makeIcon(hIcon, getLargeIcon); + disposeIcon(hIcon); + } + if (newIcon == null) { + newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon); + } + return newIcon; + } + }); if (getLargeIcon) { largeIcon = icon; } else { smallIcon = icon; } } - if (icon == null) { - icon = super.getIcon(getLargeIcon); - } return icon; } @@ -969,39 +1113,50 @@ final class Win32ShellFolder2 extends ShellFolder { private static final int LVCFMT_CENTER = 2; public ShellFolderColumnInfo[] getFolderColumns() { - ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder()); - - if (columns != null) { - List notNullColumns = - new ArrayList(); - for (int i = 0; i < columns.length; i++) { - ShellFolderColumnInfo column = columns[i]; - if (column != null) { - column.setAlignment(column.getAlignment() == LVCFMT_RIGHT - ? SwingConstants.RIGHT - : column.getAlignment() == LVCFMT_CENTER - ? SwingConstants.CENTER - : SwingConstants.LEADING); - - column.setComparator(new ColumnComparator(getIShellFolder(), i)); - - notNullColumns.add(column); + return ShellFolder.getInvoker().invoke(new Callable() { + public ShellFolderColumnInfo[] call() throws Exception { + ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder()); + + if (columns != null) { + List notNullColumns = + new ArrayList(); + for (int i = 0; i < columns.length; i++) { + ShellFolderColumnInfo column = columns[i]; + if (column != null) { + column.setAlignment(column.getAlignment() == LVCFMT_RIGHT + ? SwingConstants.RIGHT + : column.getAlignment() == LVCFMT_CENTER + ? SwingConstants.CENTER + : SwingConstants.LEADING); + + column.setComparator(new ColumnComparator(getIShellFolder(), i)); + + notNullColumns.add(column); + } + } + columns = new ShellFolderColumnInfo[notNullColumns.size()]; + notNullColumns.toArray(columns); } + return columns; } - columns = new ShellFolderColumnInfo[notNullColumns.size()]; - notNullColumns.toArray(columns); - } - return columns; + }); } - public Object getFolderColumnValue(int column) { - return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column); + public Object getFolderColumnValue(final int column) { + return ShellFolder.getInvoker().invoke(new Callable() { + public Object call() throws Exception { + return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column); + } + }); } + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native ShellFolderColumnInfo[] doGetColumnInfo(long iShellFolder2); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private native Object doGetColumnValue(long parentIShellFolder2, long childPIDL, int columnIdx); + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx); @@ -1020,17 +1175,20 @@ final class Win32ShellFolder2 extends ShellFolder { } // compares 2 objects within this folder by the specified column - public int compare(File o, File o1) { - if (o instanceof Win32ShellFolder2 - && o1 instanceof Win32ShellFolder2) { - // delegates comparison to native method - return compareIDsByColumn(parentIShellFolder, - ((Win32ShellFolder2) o).getRelativePIDL(), - ((Win32ShellFolder2) o1).getRelativePIDL(), - columnIdx); - } - return 0; + public int compare(final File o, final File o1) { + return ShellFolder.getInvoker().invoke(new Callable() { + public Integer call() throws Exception { + if (o instanceof Win32ShellFolder2 + && o1 instanceof Win32ShellFolder2) { + // delegates comparison to native method + return compareIDsByColumn(parentIShellFolder, + ((Win32ShellFolder2) o).getRelativePIDL(), + ((Win32ShellFolder2) o1).getRelativePIDL(), + columnIdx); + } + return 0; + } + }); } } - } diff --git a/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 0259e5533cde627f2a7de78c6d9b333928bbc403..563f474e2f2efe90fe8786f13d789fa56f17a1bc 100644 --- a/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -31,7 +31,10 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.*; +import java.util.concurrent.*; + import sun.security.action.LoadLibraryAction; import static sun.awt.shell.Win32ShellFolder2.*; @@ -408,4 +411,102 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { return name1.compareTo(name2); } } + + @Override + protected Invoker createInvoker() { + return new ComInvoker(); + } + + private static class ComInvoker extends ThreadPoolExecutor implements ThreadFactory, ShellFolder.Invoker { + private static Thread comThread; + + private ComInvoker() { + super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue()); + allowCoreThreadTimeOut(false); + setThreadFactory(this); + final Runnable shutdownHook = new Runnable() { + public void run() { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + shutdownNow(); + return null; + } + }); + } + }; + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + Runtime.getRuntime().addShutdownHook( + new Thread(shutdownHook) + ); + return null; + } + }); + } + + public synchronized Thread newThread(final Runnable task) { + final Runnable comRun = new Runnable() { + public void run() { + try { + initializeCom(); + task.run(); + } finally { + uninitializeCom(); + } + } + }; + comThread = + AccessController.doPrivileged( + new PrivilegedAction() { + public Thread run() { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup tg = Thread.currentThread().getThreadGroup(); + for (ThreadGroup tgn = tg; + tgn != null; + tg = tgn, tgn = tg.getParent()); + Thread thread = new Thread(tg, comRun, "Swing-Shell"); + thread.setDaemon(true); + return thread; + } + } + ); + return comThread; + } + + public T invoke(Callable task) { + try { + T result; + if (Thread.currentThread() == comThread) { + // if it's already called from the COM + // thread, we don't need to delegate the task + result = task.call(); + } else { + Future future = submit(task); + try { + result = future.get(); + } catch (InterruptedException e) { + result = null; + future.cancel(true); + } + } + return result; + } catch (Exception e) { + Throwable cause = (e instanceof ExecutionException) ? e.getCause() : e; + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + if (cause instanceof Error) { + throw (Error) cause; + } + throw new RuntimeException(cause); + } + } + } + + static native void initializeCom(); + + static native void uninitializeCom(); } diff --git a/src/windows/native/sun/windows/ShellFolder2.cpp b/src/windows/native/sun/windows/ShellFolder2.cpp index 3baf5bcf9b907ccce53ec718404d0b607ffcfea9..e88498d3af8d214f2901a2739c43db23cfc207ac 100644 --- a/src/windows/native/sun/windows/ShellFolder2.cpp +++ b/src/windows/native/sun/windows/ShellFolder2.cpp @@ -225,6 +225,34 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initIDs FID_folderType = env->GetFieldID(cls, "folderType", "Ljava/lang/String;"); } + +/* +* Class: sun_awt_shell_Win32ShellFolderManager2 +* Method: initializeCom +* Signature: ()V +*/ +JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_initializeCom + (JNIEnv* env, jclass cls) +{ + HRESULT hr = ::CoInitialize(NULL); + if (FAILED(hr)) { + char c[64]; + sprintf(c, "Could not initialize COM: HRESULT=0x%08X", hr); + JNU_ThrowInternalError(env, c); + } +} + +/* +* Class: sun_awt_shell_Win32ShellFolderManager2 +* Method: uninitializeCom +* Signature: ()V +*/ +JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom + (JNIEnv* env, jclass cls) +{ + ::CoUninitialize(); +} + static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) { // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp HRESULT hres; @@ -239,29 +267,6 @@ static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) { return (IShellIcon*)NULL; } -// Fixed 6263669 -// -// CoInitialize wrapper -// call CoInitialize to initialize COM in STA mode and check result -// RPC_E_CHANGED_MODE means COM has already been initialized in MTA mode, -// so don't set the flag to call CoUninitialize later - -BOOL CoInit(BOOL& doCoUninit) { // returns TRUE if initialized successfully - switch(::CoInitialize(NULL)) { - case S_OK: - case S_FALSE: - doCoUninit = TRUE; - return TRUE; - break; - case RPC_E_CHANGED_MODE: - doCoUninit = FALSE; - return TRUE; - break; - default: - return FALSE; - } -} - /* * Class: sun_awt_shell_Win32ShellFolder2 @@ -507,10 +512,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getAttributes0 /* * Class: sun_awt_shell_Win32ShellFolder2 - * Method: getFileSystemPath + * Method: getFileSystemPath0 * Signature: (I)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath__I +JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath0 (JNIEnv* env, jclass cls, jint csidl) { LPITEMIDLIST relPIDL; @@ -611,18 +616,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_bindToObject if (SUCCEEDED (hr)) { return (jlong)pFolder; } - if (IS_WINVISTA) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = pParent->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder); - if (doCoUninit) { - ::CoUninitialize(); - } - if (SUCCEEDED (hr)) { - return (jlong)pFolder; - } - } - } return 0; } @@ -650,7 +643,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation return NULL; } - pParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &strret); + hres = pParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &strret); + if (FAILED(hres)) { + return NULL; + } switch (strret.uType) { case STRRET_CSTR : @@ -669,10 +665,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation break; } - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return 0; - } IShellLinkW* psl; hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&psl); if (SUCCEEDED(hres)) { @@ -692,9 +684,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation } psl->Release(); } - if (doCoUninit) { - ::CoUninitialize(); - } if (SUCCEEDED(hres)) { return (jlong)pidl; @@ -741,7 +730,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0 /* * Class: sun_awt_shell_Win32ShellFolder2 * Method: getDisplayNameOf - * Signature: (JJ)Ljava/lang/String; + * Signature: (JJI)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jint attrs) @@ -833,10 +822,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex } INT index = -1; - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return (jint)index; - } HRESULT hres; // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp @@ -844,9 +829,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index); } - if (doCoUninit) { - ::CoUninitialize(); - } return (jint)index; } @@ -866,10 +848,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon } HICON hIcon = NULL; - BOOL doCoUninit; - if (!CoInit(doCoUninit)) { - return (jlong)hIcon; - } HRESULT hres; IExtractIconW* pIcon; @@ -894,9 +872,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon } pIcon->Release(); } - if (doCoUninit) { - ::CoUninitialize(); - } return (jlong)hIcon; } @@ -994,14 +969,10 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileChooserB HINSTANCE libComCtl32; HINSTANCE libShell32; - libShell32 = LoadLibrary(TEXT("shell32.dll")); if (libShell32 != NULL) { - long osVersion = GetVersion(); - BOOL isVista = (!(osVersion & 0x80000000) && (LOBYTE(LOWORD(osVersion)) >= 6)); - hBitmap = (HBITMAP)LoadImage(libShell32, - isVista ? TEXT("IDB_TB_SH_DEF_16") : MAKEINTRESOURCE(216), + IS_WINVISTA ? TEXT("IDB_TB_SH_DEF_16") : MAKEINTRESOURCE(216), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); } if (hBitmap == NULL) { @@ -1095,46 +1066,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource } -// Helper functions for workaround COM initialization: - -static HRESULT GetDetailsOfFolder( - IShellFolder2 *folder, - LPCITEMIDLIST pidl, - UINT column, - SHELLDETAILS *psd) -{ - HRESULT hr = folder->GetDetailsOf(pidl, column, psd); - if (IS_WINVISTA && FAILED (hr)) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = folder->GetDetailsOf(pidl, column, psd); - if (doCoUninit) { - ::CoUninitialize(); - } - } - } - return hr; -} - -static HRESULT GetDetailsOf( - IShellDetails *details, - LPCITEMIDLIST pidl, - UINT column, - SHELLDETAILS *psd) -{ - HRESULT hr = details->GetDetailsOf(pidl, column, psd); - if (IS_WINVISTA && FAILED (hr)) { - BOOL doCoUninit; - if (CoInit(doCoUninit)) { - hr = details->GetDetailsOf(pidl, column, psd); - if (doCoUninit) { - ::CoUninitialize(); - } - } - } - return hr; -} - /* * Helper function for creating Java column info object */ @@ -1187,7 +1118,7 @@ JNIEXPORT jobjectArray JNICALL int colNum = -1; hr = S_OK; do{ - hr = GetDetailsOfFolder(pIShellFolder2, NULL, ++colNum, &sd); + hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd); } while (SUCCEEDED (hr)); jobjectArray columns = @@ -1202,7 +1133,7 @@ JNIEXPORT jobjectArray JNICALL colNum = 0; hr = S_OK; while (SUCCEEDED (hr)) { - hr = GetDetailsOfFolder(pIShellFolder2, NULL, colNum, &sd); + hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd); if (SUCCEEDED (hr)) { hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags); @@ -1232,7 +1163,7 @@ JNIEXPORT jobjectArray JNICALL int colNum = -1; hr = S_OK; do{ - hr = GetDetailsOf(pIShellDetails, NULL, ++colNum, &sd); + hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd); } while (SUCCEEDED (hr)); jobjectArray columns = @@ -1246,7 +1177,7 @@ JNIEXPORT jobjectArray JNICALL colNum = 0; hr = S_OK; while (SUCCEEDED (hr)) { - hr = GetDetailsOf(pIShellDetails, NULL, colNum, &sd); + hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd); if (SUCCEEDED (hr)) { jobject column = CreateColumnInfo(env, &columnClass, &columnConstructor, @@ -1288,7 +1219,7 @@ JNIEXPORT jobject JNICALL if(SUCCEEDED (hr)) { // The folder exposes IShellFolder2 interface IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown; - hr = GetDetailsOfFolder(pIShellFolder2, pidl, (UINT)columnIdx, &sd); + hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd); pIShellFolder2->Release(); if (SUCCEEDED (hr)) { STRRET strRet = sd.str; @@ -1300,7 +1231,7 @@ JNIEXPORT jobject JNICALL if(SUCCEEDED (hr)) { // The folder exposes IShellDetails interface IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown; - hr = GetDetailsOf(pIShellDetails, pidl, (UINT)columnIdx, &sd); + hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd); pIShellDetails->Release(); if (SUCCEEDED (hr)) { STRRET strRet = sd.str; diff --git a/test/javax/swing/JFileChooser/6570445/bug6570445.java b/test/javax/swing/JFileChooser/6570445/bug6570445.java new file mode 100644 index 0000000000000000000000000000000000000000..f746edaee5468688b6fcef5028555c537ae7d28d --- /dev/null +++ b/test/javax/swing/JFileChooser/6570445/bug6570445.java @@ -0,0 +1,20 @@ +/* + * @test + * @bug 6570445 + * @summary Checks if Win32ShellFolder2's COM-using methods work under a security manager + * @author Leonid Popov + */ + +import javax.swing.filechooser.FileSystemView; + +public class bug6570445 { + public static void main(String[] args) { + System.setSecurityManager(new SecurityManager()); + + // The next line of code forces FileSystemView to request data from Win32ShellFolder2, + // what causes an exception if a security manager installed (see the bug 6570445 description) + FileSystemView.getFileSystemView().getRoots(); + + System.out.println("Passed."); + } +}