提交 26b463b3 编写于 作者: R rupashka

6491795: COM should be initialized for Shell API calls in ShellFolder2.cpp

Reviewed-by: peterz, loneid
上级 5f55e0e8
...@@ -27,6 +27,7 @@ package javax.swing.plaf.basic; ...@@ -27,6 +27,7 @@ package javax.swing.plaf.basic;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
import java.util.concurrent.Callable;
import javax.swing.*; import javax.swing.*;
import javax.swing.filechooser.*; import javax.swing.filechooser.*;
import javax.swing.event.*; import javax.swing.event.*;
...@@ -223,17 +224,14 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -223,17 +224,14 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
this.fid = fid; this.fid = fid;
} }
private void invokeLater(DoChangeContents runnable) {
runnables.addElement(runnable);
SwingUtilities.invokeLater(runnable);
}
public void run() { public void run() {
run0(); run0();
setBusy(false, fid); setBusy(false, fid);
} }
public void run0() { public void run0() {
DoChangeContents doChangeContents = ShellFolder.getInvoker().invoke(new Callable<DoChangeContents>() {
public DoChangeContents call() throws Exception {
FileSystemView fileSystem = filechooser.getFileSystemView(); FileSystemView fileSystem = filechooser.getFileSystemView();
File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
...@@ -241,7 +239,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -241,7 +239,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
Vector<File> acceptsList = new Vector<File>(); Vector<File> acceptsList = new Vector<File>();
if (isInterrupted()) { if (isInterrupted()) {
return; return null;
} }
// run through the file list, add directories and selectable files to fileCache // run through the file list, add directories and selectable files to fileCache
...@@ -252,7 +250,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -252,7 +250,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
} }
if (isInterrupted()) { if (isInterrupted()) {
return; return null;
} }
// First sort alphabetically by filename // First sort alphabetically by filename
...@@ -261,7 +259,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -261,7 +259,7 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
Vector<File> newDirectories = new Vector<File>(50); Vector<File> newDirectories = new Vector<File>(50);
Vector<File> newFiles = new Vector<File>(); Vector<File> newFiles = new Vector<File>();
// run through list grabbing directories in chunks of ten // run through list grabbing directories in chunks of ten
for(int i = 0; i < acceptsList.size(); i++) { for (int i = 0; i < acceptsList.size(); i++) {
File f = acceptsList.elementAt(i); File f = acceptsList.elementAt(i);
boolean isTraversable = filechooser.isTraversable(f); boolean isTraversable = filechooser.isTraversable(f);
if (isTraversable) { if (isTraversable) {
...@@ -269,8 +267,8 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -269,8 +267,8 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
} else if (!isTraversable && filechooser.isFileSelectionEnabled()) { } else if (!isTraversable && filechooser.isFileSelectionEnabled()) {
newFiles.addElement(f); newFiles.addElement(f);
} }
if(isInterrupted()) { if (isInterrupted()) {
return; return null;
} }
} }
...@@ -298,11 +296,10 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -298,11 +296,10 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
} }
if (start >= 0 && end > start if (start >= 0 && end > start
&& newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) { && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) {
if(isInterrupted()) { if (isInterrupted()) {
return; return null;
} }
invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid)); return new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid);
newFileCache = null;
} }
} else if (newSize < oldSize) { } else if (newSize < oldSize) {
//see if interval is removed //see if interval is removed
...@@ -317,19 +314,25 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh ...@@ -317,19 +314,25 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
} }
if (start >= 0 && end > start if (start >= 0 && end > start
&& fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) { && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) {
if(isInterrupted()) { if (isInterrupted()) {
return; return null;
} }
invokeLater(new DoChangeContents(null, 0, new Vector<File>(fileCache.subList(start, end)), return new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), start, fid);
start, fid));
newFileCache = null;
} }
} }
if (newFileCache != null && !fileCache.equals(newFileCache)) { if (!fileCache.equals(newFileCache)) {
if (isInterrupted()) { if (isInterrupted()) {
cancelRunnables(runnables); cancelRunnables(runnables);
} }
invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid)); return new DoChangeContents(newFileCache, 0, fileCache, 0, fid);
}
return null;
}
});
if (doChangeContents != null) {
runnables.addElement(doChangeContents);
SwingUtilities.invokeLater(doChangeContents);
} }
} }
......
...@@ -31,6 +31,7 @@ import java.awt.Toolkit; ...@@ -31,6 +31,7 @@ import java.awt.Toolkit;
import java.io.*; import java.io.*;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.*; import java.util.*;
import java.util.concurrent.Callable;
/** /**
* @author Michael Martak * @author Michael Martak
...@@ -461,6 +462,35 @@ public abstract class ShellFolder extends File { ...@@ -461,6 +462,35 @@ public abstract class ShellFolder extends File {
return null; 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> T invoke(Callable<T> task);
}
/** /**
* Provides a default comparator for the default column set * Provides a default comparator for the default column set
*/ */
......
...@@ -27,6 +27,7 @@ package sun.awt.shell; ...@@ -27,6 +27,7 @@ package sun.awt.shell;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.concurrent.Callable;
/** /**
* @author Michael Martak * @author Michael Martak
...@@ -96,9 +97,23 @@ class ShellFolderManager { ...@@ -96,9 +97,23 @@ class ShellFolderManager {
} }
public boolean isFileSystemRoot(File dir) { public boolean isFileSystemRoot(File dir) {
if (dir instanceof ShellFolder && !((ShellFolder)dir).isFileSystem()) { if (dir instanceof ShellFolder && !((ShellFolder) dir).isFileSystem()) {
return false; return false;
} }
return (dir.getParentFile() == null); return (dir.getParentFile() == null);
} }
protected ShellFolder.Invoker createInvoker() {
return new DirectInvoker();
}
private static class DirectInvoker implements ShellFolder.Invoker {
public <T> T invoke(Callable<T> task) {
try {
return task.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
} }
...@@ -34,6 +34,7 @@ import java.text.DateFormat; ...@@ -34,6 +34,7 @@ import java.text.DateFormat;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*; import javax.swing.border.*;
...@@ -900,6 +901,16 @@ public class FilePane extends JPanel implements PropertyChangeListener { ...@@ -900,6 +901,16 @@ public class FilePane extends JPanel implements PropertyChangeListener {
} }
} }
@Override
public void sort() {
ShellFolder.getInvoker().invoke(new Callable<Void>() {
public Void call() throws Exception {
DetailsTableRowSorter.super.sort();
return null;
}
});
}
public void modelStructureChanged() { public void modelStructureChanged() {
super.modelStructureChanged(); super.modelStructureChanged();
updateComparators(detailsTableModel.getColumns()); updateComparators(detailsTableModel.getColumns());
......
...@@ -32,6 +32,7 @@ import java.io.File; ...@@ -32,6 +32,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.*;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
// NOTE: This class supersedes Win32ShellFolder, which was removed from // NOTE: This class supersedes Win32ShellFolder, which was removed from
...@@ -184,6 +185,8 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -184,6 +185,8 @@ final class Win32ShellFolder2 extends ShellFolder {
boolean disposed; boolean disposed;
public void dispose() { public void dispose() {
if (disposed) return; if (disposed) return;
ShellFolder.getInvoker().invoke(new Callable<Void>() {
public Void call() throws Exception {
if (relativePIDL != 0) { if (relativePIDL != 0) {
releasePIDL(relativePIDL); releasePIDL(relativePIDL);
} }
...@@ -193,6 +196,9 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -193,6 +196,9 @@ final class Win32ShellFolder2 extends ShellFolder {
if (pIShellFolder != 0) { if (pIShellFolder != 0) {
releaseIShellFolder(pIShellFolder); releaseIShellFolder(pIShellFolder);
} }
return null;
}
});
disposed = true; disposed = true;
} }
} }
...@@ -218,17 +224,23 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -218,17 +224,23 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
private boolean isPersonal; 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 * Create a system special shell folder, such as the
* desktop or Network Neighborhood. * desktop or Network Neighborhood.
*/ */
Win32ShellFolder2(int csidl) throws IOException { Win32ShellFolder2(final int csidl) throws IOException {
// Desktop is parent of DRIVES and NETWORK, not necessarily // Desktop is parent of DRIVES and NETWORK, not necessarily
// other special shell folders. // other special shell folders.
super(null, super(null, composePathForCsidl(csidl));
(getFileSystemPath(csidl) == null) ShellFolder.getInvoker().invoke(new Callable<Void>() {
? ("ShellFolder: 0x"+Integer.toHexString(csidl)) : getFileSystemPath(csidl)); public Void call() throws Exception {
if (csidl == DESKTOP) { if (csidl == DESKTOP) {
initDesktop(); initDesktop();
} else { } else {
...@@ -251,7 +263,7 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -251,7 +263,7 @@ final class Win32ShellFolder2 extends ShellFolder {
// Now we know that parent isn't immediate to 'this' because it // Now we know that parent isn't immediate to 'this' because it
// has a continued ID list. Create a shell folder for this child // has a continued ID list. Create a shell folder for this child
// pidl and make it the new 'parent'. // pidl and make it the new 'parent'.
parent = new Win32ShellFolder2((Win32ShellFolder2)parent, childPIDL); parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL);
} else { } else {
// No grandchildren means we have arrived at the parent of 'this', // No grandchildren means we have arrived at the parent of 'this',
// and childPIDL is directly relative to parent. // and childPIDL is directly relative to parent.
...@@ -262,6 +274,9 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -262,6 +274,9 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
} }
} }
return null;
}
});
sun.java2d.Disposer.addRecord(this, disposer); sun.java2d.Disposer.addRecord(this, disposer);
} }
...@@ -281,17 +296,26 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -281,17 +296,26 @@ final class Win32ShellFolder2 extends ShellFolder {
/** /**
* Creates a shell folder with a parent and relative PIDL * Creates a shell folder with a parent and relative PIDL
*/ */
Win32ShellFolder2(Win32ShellFolder2 parent, long relativePIDL) { Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) {
super(parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL)); super(parent,
ShellFolder.getInvoker().invoke(new Callable<String>() {
public String call() throws Exception {
return getFileSystemPath(parent.getIShellFolder(), relativePIDL);
}
})
);
this.disposer.relativePIDL = relativePIDL; this.disposer.relativePIDL = relativePIDL;
getAbsolutePath(); getAbsolutePath();
sun.java2d.Disposer.addRecord(this, disposer); sun.java2d.Disposer.addRecord(this, disposer);
} }
// Initializes the desktop shell folder // 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(); private native void initDesktop();
// Initializes a special, non-file system shell folder // Initializes a special, non-file system shell folder
// from one of the above constants // 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); private native void initSpecial(long desktopIShellFolder, int csidl);
/** Marks this folder as being the My Documents (Personal) folder */ /** Marks this folder as being the My Documents (Personal) folder */
...@@ -311,6 +335,8 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -311,6 +335,8 @@ final class Win32ShellFolder2 extends ShellFolder {
* drive (normally "C:\"). * drive (normally "C:\").
*/ */
protected Object writeReplace() throws java.io.ObjectStreamException { protected Object writeReplace() throws java.io.ObjectStreamException {
return ShellFolder.getInvoker().invoke(new Callable<File>() {
public File call() throws Exception {
if (isFileSystem()) { if (isFileSystem()) {
return new File(getPath()); return new File(getPath());
} else { } else {
...@@ -320,7 +346,7 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -320,7 +346,7 @@ final class Win32ShellFolder2 extends ShellFolder {
if (driveRoots != null) { if (driveRoots != null) {
for (int i = 0; i < driveRoots.length; i++) { for (int i = 0; i < driveRoots.length; i++) {
if (driveRoots[i] instanceof Win32ShellFolder2) { if (driveRoots[i] instanceof Win32ShellFolder2) {
Win32ShellFolder2 sf = (Win32ShellFolder2)driveRoots[i]; Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i];
if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) { if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) {
return new File(sf.getPath()); return new File(sf.getPath());
} }
...@@ -332,6 +358,8 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -332,6 +358,8 @@ final class Win32ShellFolder2 extends ShellFolder {
return new File("C:\\"); return new File("C:\\");
} }
} }
});
}
/** /**
...@@ -364,6 +392,7 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -364,6 +392,7 @@ final class Win32ShellFolder2 extends ShellFolder {
static native void releasePIDL(long pIDL); static native void releasePIDL(long pIDL);
// Release an IShellFolder object // 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); private static native void releaseIShellFolder(long pIShellFolder);
/** /**
...@@ -371,18 +400,28 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -371,18 +400,28 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
public long getIShellFolder() { public long getIShellFolder() {
if (disposer.pIShellFolder == 0) { if (disposer.pIShellFolder == 0) {
disposer.pIShellFolder =
ShellFolder.getInvoker().invoke(new Callable<Long>() {
public Long call() throws Exception {
assert(isDirectory()); assert(isDirectory());
assert(parent != null); assert(parent != null);
long parentIShellFolder = getParentIShellFolder(); long parentIShellFolder = getParentIShellFolder();
if (parentIShellFolder == 0) { if (parentIShellFolder == 0) {
throw new InternalError("Parent IShellFolder was null for " + getAbsolutePath()); throw new InternalError("Parent IShellFolder was null for "
+ getAbsolutePath());
} }
// We are a directory with a parent and a relative PIDL. // 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. // We want to bind to the parent so we get an
disposer.pIShellFolder = bindToObject(parentIShellFolder, disposer.relativePIDL); // IShellFolder instance associated with us.
if (disposer.pIShellFolder == 0) { long pIShellFolder = bindToObject(parentIShellFolder,
throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent"); disposer.relativePIDL);
if (pIShellFolder == 0) {
throw new InternalError("Unable to bind "
+ getAbsolutePath() + " to parent");
}
return pIShellFolder;
} }
});
} }
return disposer.pIShellFolder; return disposer.pIShellFolder;
} }
...@@ -472,24 +511,42 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -472,24 +511,42 @@ final class Win32ShellFolder2 extends ShellFolder {
return false; return false;
} }
private static boolean pidlsEqual(long pIShellFolder, long pidl1, long pidl2) { private static boolean pidlsEqual(final long pIShellFolder, final long pidl1, final long pidl2) {
return ShellFolder.getInvoker().invoke(new Callable<Boolean>() {
public Boolean call() throws Exception {
return (compareIDs(pIShellFolder, pidl1, pidl2) == 0); 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 static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2);
private Boolean cachedIsFileSystem;
/** /**
* @return Whether this is a file system shell folder * @return Whether this is a file system shell folder
*/ */
public boolean isFileSystem() { public synchronized boolean isFileSystem() {
return hasAttribute(ATTRIB_FILESYSTEM); if (cachedIsFileSystem == null) {
cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM);
}
return cachedIsFileSystem;
} }
/** /**
* Return whether the given attribute flag is set for this object * Return whether the given attribute flag is set for this object
*/ */
public boolean hasAttribute(int attribute) { public boolean hasAttribute(final int attribute) {
return ShellFolder.getInvoker().invoke(new Callable<Boolean>() {
public Boolean call() throws Exception {
// Caching at this point doesn't seem to be cost efficient // Caching at this point doesn't seem to be cost efficient
return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0; return (getAttributes0(getParentIShellFolder(),
getRelativePIDL(), attribute)
& attribute) != 0;
}
});
} }
/** /**
...@@ -498,11 +555,15 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -498,11 +555,15 @@ final class Win32ShellFolder2 extends ShellFolder {
* Could plausibly be used for attribute caching but have to be * Could plausibly be used for attribute caching but have to be
* very careful not to touch network drives and file system roots * very careful not to touch network drives and file system roots
* with a full attrsMask * 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); private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask);
// Return the path to the underlying file system object // Return the path to the underlying file system object
private static String getFileSystemPath(long parentIShellFolder, long relativePIDL) { private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) {
return ShellFolder.getInvoker().invoke(new Callable<String>() {
public String call() throws Exception {
int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER; int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() && if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) { getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
...@@ -514,10 +575,22 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -514,10 +575,22 @@ final class Win32ShellFolder2 extends ShellFolder {
return s; return s;
} }
} }
return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING); return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING);
}
});
} }
// Needs to be accessible to Win32ShellFolderManager2 // 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<String>() {
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. // Return whether the path is a network root.
// Path is assumed to be non-null // Path is assumed to be non-null
...@@ -557,24 +630,33 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -557,24 +630,33 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
// Returns an IEnumIDList interface for an IShellFolder. The value // Returns an IEnumIDList interface for an IShellFolder. The value
// returned must be released using releaseEnumObjects(). // returned must be released using releaseEnumObjects().
private long getEnumObjects(long pIShellFolder, boolean includeHiddenFiles) { private long getEnumObjects(long pIShellFolder, final boolean includeHiddenFiles) {
boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder()); final boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder());
return ShellFolder.getInvoker().invoke(new Callable<Long>() {
public Long call() throws Exception {
return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles); return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
} }
});
}
// Returns an IEnumIDList interface for an IShellFolder. The value // Returns an IEnumIDList interface for an IShellFolder. The value
// returned must be released using releaseEnumObjects(). // 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, private native long getEnumObjects(long pIShellFolder, boolean isDesktop,
boolean includeHiddenFiles); boolean includeHiddenFiles);
// Returns the next sequential child as a relative PIDL // Returns the next sequential child as a relative PIDL
// from an IEnumIDList interface. The value returned must // from an IEnumIDList interface. The value returned must
// be released using releasePIDL(). // 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); private native long getNextChild(long pEnumObjects);
// Releases the IEnumIDList interface // 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); private native void releaseEnumObjects(long pEnumObjects);
// Returns the IShellFolder of a child from a parent IShellFolder // Returns the IShellFolder of a child from a parent IShellFolder
// and a relative PIDL. The value returned must be released // and a relative PIDL. The value returned must be released
// using releaseIShellFolder(). // 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); private static native long bindToObject(long parentIShellFolder, long pIDL);
/** /**
...@@ -582,11 +664,14 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -582,11 +664,14 @@ final class Win32ShellFolder2 extends ShellFolder {
* object. The array will be empty if the folder is empty. Returns * object. The array will be empty if the folder is empty. Returns
* <code>null</code> if this shellfolder does not denote a directory. * <code>null</code> if this shellfolder does not denote a directory.
*/ */
public File[] listFiles(boolean includeHiddenFiles) { public File[] listFiles(final boolean includeHiddenFiles) {
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (security != null) { if (security != null) {
security.checkRead(getPath()); security.checkRead(getPath());
} }
return ShellFolder.getInvoker().invoke(new Callable<File[]>() {
public File[] call() throws Exception {
if (!isDirectory()) { if (!isDirectory()) {
return null; return null;
} }
...@@ -611,20 +696,17 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -611,20 +696,17 @@ final class Win32ShellFolder2 extends ShellFolder {
long childPIDL; long childPIDL;
int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR; int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
do { do {
if (Thread.currentThread().isInterrupted()) {
return new File[0];
}
childPIDL = getNextChild(pEnumObjects); childPIDL = getNextChild(pEnumObjects);
boolean releasePIDL = true; boolean releasePIDL = true;
if (childPIDL != 0 && if (childPIDL != 0 &&
(getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) { (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
Win32ShellFolder2 childFolder = null; Win32ShellFolder2 childFolder;
if (this.equals(desktop) if (Win32ShellFolder2.this.equals(desktop)
&& personal != null && personal != null
&& pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) { && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
childFolder = personal; childFolder = personal;
} else { } else {
childFolder = new Win32ShellFolder2(this, childPIDL); childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL);
releasePIDL = false; releasePIDL = false;
} }
list.add(childFolder); list.add(childFolder);
...@@ -632,10 +714,14 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -632,10 +714,14 @@ final class Win32ShellFolder2 extends ShellFolder {
if (releasePIDL) { if (releasePIDL) {
releasePIDL(childPIDL); releasePIDL(childPIDL);
} }
} while (childPIDL != 0); } while (childPIDL != 0 && !Thread.currentThread().isInterrupted());
releaseEnumObjects(pEnumObjects); releaseEnumObjects(pEnumObjects);
} }
return list.toArray(new ShellFolder[list.size()]); return Thread.currentThread().isInterrupted()
? new File[0]
: list.toArray(new ShellFolder[list.size()]);
}
});
} }
...@@ -644,18 +730,21 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -644,18 +730,21 @@ final class Win32ShellFolder2 extends ShellFolder {
* *
* @return The child shellfolder, or null if not found. * @return The child shellfolder, or null if not found.
*/ */
Win32ShellFolder2 getChildByPath(String filePath) { Win32ShellFolder2 getChildByPath(final String filePath) {
return ShellFolder.getInvoker().invoke(new Callable<Win32ShellFolder2>() {
public Win32ShellFolder2 call() throws Exception {
long pIShellFolder = getIShellFolder(); long pIShellFolder = getIShellFolder();
long pEnumObjects = getEnumObjects(pIShellFolder, true); long pEnumObjects = getEnumObjects(pIShellFolder, true);
Win32ShellFolder2 child = null; Win32ShellFolder2 child = null;
long childPIDL; long childPIDL = 0;
while ((childPIDL = getNextChild(pEnumObjects)) != 0) { while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) { if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
String path = getFileSystemPath(pIShellFolder, childPIDL); String path = getFileSystemPath(pIShellFolder, childPIDL);
if (path != null && path.equalsIgnoreCase(filePath)) { if (path != null && path.equalsIgnoreCase(filePath)) {
long childIShellFolder = bindToObject(pIShellFolder, childPIDL); long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path); child = new Win32ShellFolder2(Win32ShellFolder2.this,
childIShellFolder, childPIDL, path);
break; break;
} }
} }
...@@ -664,13 +753,20 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -664,13 +753,20 @@ final class Win32ShellFolder2 extends ShellFolder {
releaseEnumObjects(pEnumObjects); releaseEnumObjects(pEnumObjects);
return child; return child;
} }
});
}
private Boolean cachedIsLink;
/** /**
* @return Whether this shell folder is a link * @return Whether this shell folder is a link
*/ */
public boolean isLink() { public synchronized boolean isLink() {
return hasAttribute(ATTRIB_LINK); if (cachedIsLink == null) {
cachedIsLink = hasAttribute(ATTRIB_LINK);
}
return cachedIsLink;
} }
/** /**
...@@ -682,6 +778,7 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -682,6 +778,7 @@ final class Win32ShellFolder2 extends ShellFolder {
// Return the link location of a shell folder // 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, private static native long getLinkLocation(long parentIShellFolder,
long relativePIDL, boolean resolve); long relativePIDL, boolean resolve);
...@@ -693,7 +790,9 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -693,7 +790,9 @@ final class Win32ShellFolder2 extends ShellFolder {
return getLinkLocation(true); return getLinkLocation(true);
} }
private ShellFolder getLinkLocation(boolean resolve) { private ShellFolder getLinkLocation(final boolean resolve) {
return ShellFolder.getInvoker().invoke(new Callable<ShellFolder>() {
public ShellFolder call() throws Exception {
if (!isLink()) { if (!isLink()) {
return null; return null;
} }
...@@ -713,18 +812,30 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -713,18 +812,30 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
return location; return location;
} }
});
}
// Parse a display name into a PIDL relative to the current IShellFolder. // 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 { try {
return ShellFolder.getInvoker().invoke(new Callable<Long>() {
public Long call() throws Exception {
return parseDisplayName0(getIShellFolder(), name); return parseDisplayName0(getIShellFolder(), name);
} catch (IOException e) { }
});
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw new FileNotFoundException("Could not find file " + name); 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; private static native long parseDisplayName0(long pIShellFolder, String name) throws IOException;
// Return the display name of a shell folder // 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, private static native String getDisplayNameOf(long parentIShellFolder,
long relativePIDL, long relativePIDL,
int attrs); int attrs);
...@@ -734,12 +845,19 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -734,12 +845,19 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
public String getDisplayName() { public String getDisplayName() {
if (displayName == null) { if (displayName == null) {
displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL); displayName =
ShellFolder.getInvoker().invoke(new Callable<String>() {
public String call() throws Exception {
return getDisplayNameOf(getParentIShellFolder(),
getRelativePIDL(), SHGDN_NORMAL);
}
});
} }
return displayName; return displayName;
} }
// Return the folder type of a shell folder // 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); private static native String getFolderType(long pIDL);
/** /**
...@@ -747,7 +865,13 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -747,7 +865,13 @@ final class Win32ShellFolder2 extends ShellFolder {
*/ */
public String getFolderType() { public String getFolderType() {
if (folderType == null) { if (folderType == null) {
folderType = getFolderType(getAbsolutePIDL()); final long absolutePIDL = getAbsolutePIDL();
folderType =
ShellFolder.getInvoker().invoke(new Callable<String>() {
public String call() throws Exception {
return getFolderType(absolutePIDL);
}
});
} }
return folderType; return folderType;
} }
...@@ -774,11 +898,16 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -774,11 +898,16 @@ final class Win32ShellFolder2 extends ShellFolder {
private static Map smallLinkedSystemImages = new HashMap(); private static Map smallLinkedSystemImages = new HashMap();
private static Map largeLinkedSystemImages = 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); 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); private static native int getIconIndex(long parentIShellIcon, long relativePIDL);
// Return the icon of a file system shell folder in the form of an HICON // Return the icon of a file system shell folder in the form of an HICON
private static native long getIcon(String absolutePath, boolean getLargeIcon); 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, private static native long extractIcon(long parentIShellFolder, long relativePIDL,
boolean getLargeIcon); boolean getLargeIcon);
...@@ -799,7 +928,12 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -799,7 +928,12 @@ final class Win32ShellFolder2 extends ShellFolder {
private long getIShellIcon() { private long getIShellIcon() {
if (pIShellIcon == -1L) { if (pIShellIcon == -1L) {
pIShellIcon = getIShellIcon(getIShellFolder()); pIShellIcon =
ShellFolder.getInvoker().invoke(new Callable<Long>() {
public Long call() throws Exception {
return getIShellIcon(getIShellFolder());
}
});
} }
return pIShellIcon; return pIShellIcon;
} }
...@@ -850,13 +984,19 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -850,13 +984,19 @@ final class Win32ShellFolder2 extends ShellFolder {
/** /**
* @return The icon image used to display this shell folder * @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; Image icon = getLargeIcon ? largeIcon : smallIcon;
if (icon == null) { if (icon == null) {
long parentIShellIcon = (parent != null) ? ((Win32ShellFolder2)parent).getIShellIcon() : 0L; icon =
ShellFolder.getInvoker().invoke(new Callable<Image>() {
public Image call() throws Exception {
Image newIcon = null;
if (isFileSystem()) {
long parentIShellIcon = (parent != null)
? ((Win32ShellFolder2) parent).getIShellIcon()
: 0L;
long relativePIDL = getRelativePIDL(); long relativePIDL = getRelativePIDL();
if (isFileSystem()) {
// These are cached per type (using the index in the system image list) // These are cached per type (using the index in the system image list)
int index = getIconIndex(parentIShellIcon, relativePIDL); int index = getIconIndex(parentIShellIcon, relativePIDL);
if (index > 0) { if (index > 0) {
...@@ -866,34 +1006,38 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -866,34 +1006,38 @@ final class Win32ShellFolder2 extends ShellFolder {
} else { } else {
imageCache = getLargeIcon ? largeSystemImages : smallSystemImages; imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
} }
icon = (Image)imageCache.get(Integer.valueOf(index)); newIcon = (Image) imageCache.get(Integer.valueOf(index));
if (icon == null) { if (newIcon == null) {
long hIcon = getIcon(getAbsolutePath(), getLargeIcon); long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
icon = makeIcon(hIcon, getLargeIcon); newIcon = makeIcon(hIcon, getLargeIcon);
disposeIcon(hIcon); disposeIcon(hIcon);
if (icon != null) { if (newIcon != null) {
imageCache.put(Integer.valueOf(index), icon); imageCache.put(Integer.valueOf(index), newIcon);
} }
} }
} }
} }
if (icon == null) { if (newIcon == null) {
// These are only cached per object // These are only cached per object
long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon); long hIcon = extractIcon(getParentIShellFolder(),
icon = makeIcon(hIcon, getLargeIcon); getRelativePIDL(), getLargeIcon);
newIcon = makeIcon(hIcon, getLargeIcon);
disposeIcon(hIcon); disposeIcon(hIcon);
} }
if (newIcon == null) {
newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon);
}
return newIcon;
}
});
if (getLargeIcon) { if (getLargeIcon) {
largeIcon = icon; largeIcon = icon;
} else { } else {
smallIcon = icon; smallIcon = icon;
} }
} }
if (icon == null) {
icon = super.getIcon(getLargeIcon);
}
return icon; return icon;
} }
...@@ -969,6 +1113,8 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -969,6 +1113,8 @@ final class Win32ShellFolder2 extends ShellFolder {
private static final int LVCFMT_CENTER = 2; private static final int LVCFMT_CENTER = 2;
public ShellFolderColumnInfo[] getFolderColumns() { public ShellFolderColumnInfo[] getFolderColumns() {
return ShellFolder.getInvoker().invoke(new Callable<ShellFolderColumnInfo[]>() {
public ShellFolderColumnInfo[] call() throws Exception {
ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder()); ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
if (columns != null) { if (columns != null) {
...@@ -993,15 +1139,24 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -993,15 +1139,24 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
return columns; return columns;
} }
});
}
public Object getFolderColumnValue(int column) { public Object getFolderColumnValue(final int column) {
return ShellFolder.getInvoker().invoke(new Callable<Object>() {
public Object call() throws Exception {
return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column); 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); 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); 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); private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx);
...@@ -1020,7 +1175,9 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -1020,7 +1175,9 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
// compares 2 objects within this folder by the specified column // compares 2 objects within this folder by the specified column
public int compare(File o, File o1) { public int compare(final File o, final File o1) {
return ShellFolder.getInvoker().invoke(new Callable<Integer>() {
public Integer call() throws Exception {
if (o instanceof Win32ShellFolder2 if (o instanceof Win32ShellFolder2
&& o1 instanceof Win32ShellFolder2) { && o1 instanceof Win32ShellFolder2) {
// delegates comparison to native method // delegates comparison to native method
...@@ -1031,6 +1188,7 @@ final class Win32ShellFolder2 extends ShellFolder { ...@@ -1031,6 +1188,7 @@ final class Win32ShellFolder2 extends ShellFolder {
} }
return 0; return 0;
} }
});
}
} }
} }
...@@ -31,7 +31,10 @@ import java.io.File; ...@@ -31,7 +31,10 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*; import java.util.*;
import java.util.concurrent.*;
import sun.security.action.LoadLibraryAction; import sun.security.action.LoadLibraryAction;
import static sun.awt.shell.Win32ShellFolder2.*; import static sun.awt.shell.Win32ShellFolder2.*;
...@@ -408,4 +411,102 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { ...@@ -408,4 +411,102 @@ public class Win32ShellFolderManager2 extends ShellFolderManager {
return name1.compareTo(name2); 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<Runnable>());
allowCoreThreadTimeOut(false);
setThreadFactory(this);
final Runnable shutdownHook = new Runnable() {
public void run() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
shutdownNow();
return null;
}
});
}
};
AccessController.doPrivileged(new PrivilegedAction<Void>() {
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<Thread>() {
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> T invoke(Callable<T> 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<T> 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();
} }
...@@ -225,6 +225,34 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initIDs ...@@ -225,6 +225,34 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initIDs
FID_folderType = env->GetFieldID(cls, "folderType", "Ljava/lang/String;"); 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) { static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) {
// http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp
HRESULT hres; HRESULT hres;
...@@ -239,29 +267,6 @@ static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) { ...@@ -239,29 +267,6 @@ static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) {
return (IShellIcon*)NULL; 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 * Class: sun_awt_shell_Win32ShellFolder2
...@@ -507,10 +512,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getAttributes0 ...@@ -507,10 +512,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getAttributes0
/* /*
* Class: sun_awt_shell_Win32ShellFolder2 * Class: sun_awt_shell_Win32ShellFolder2
* Method: getFileSystemPath * Method: getFileSystemPath0
* Signature: (I)Ljava/lang/String; * 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) (JNIEnv* env, jclass cls, jint csidl)
{ {
LPITEMIDLIST relPIDL; LPITEMIDLIST relPIDL;
...@@ -611,18 +616,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_bindToObject ...@@ -611,18 +616,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_bindToObject
if (SUCCEEDED (hr)) { if (SUCCEEDED (hr)) {
return (jlong)pFolder; 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; return 0;
} }
...@@ -650,7 +643,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation ...@@ -650,7 +643,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation
return NULL; 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) { switch (strret.uType) {
case STRRET_CSTR : case STRRET_CSTR :
...@@ -669,10 +665,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation ...@@ -669,10 +665,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation
break; break;
} }
BOOL doCoUninit;
if (!CoInit(doCoUninit)) {
return 0;
}
IShellLinkW* psl; IShellLinkW* psl;
hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&psl); hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&psl);
if (SUCCEEDED(hres)) { if (SUCCEEDED(hres)) {
...@@ -692,9 +684,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation ...@@ -692,9 +684,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation
} }
psl->Release(); psl->Release();
} }
if (doCoUninit) {
::CoUninitialize();
}
if (SUCCEEDED(hres)) { if (SUCCEEDED(hres)) {
return (jlong)pidl; return (jlong)pidl;
...@@ -741,7 +730,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0 ...@@ -741,7 +730,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0
/* /*
* Class: sun_awt_shell_Win32ShellFolder2 * Class: sun_awt_shell_Win32ShellFolder2
* Method: getDisplayNameOf * Method: getDisplayNameOf
* Signature: (JJ)Ljava/lang/String; * Signature: (JJI)Ljava/lang/String;
*/ */
JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf
(JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jint attrs) (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jint attrs)
...@@ -833,10 +822,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex ...@@ -833,10 +822,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex
} }
INT index = -1; INT index = -1;
BOOL doCoUninit;
if (!CoInit(doCoUninit)) {
return (jint)index;
}
HRESULT hres; HRESULT hres;
// http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp // 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 ...@@ -844,9 +829,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex
hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index); hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index);
} }
if (doCoUninit) {
::CoUninitialize();
}
return (jint)index; return (jint)index;
} }
...@@ -866,10 +848,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon ...@@ -866,10 +848,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
} }
HICON hIcon = NULL; HICON hIcon = NULL;
BOOL doCoUninit;
if (!CoInit(doCoUninit)) {
return (jlong)hIcon;
}
HRESULT hres; HRESULT hres;
IExtractIconW* pIcon; IExtractIconW* pIcon;
...@@ -894,9 +872,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon ...@@ -894,9 +872,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
} }
pIcon->Release(); pIcon->Release();
} }
if (doCoUninit) {
::CoUninitialize();
}
return (jlong)hIcon; return (jlong)hIcon;
} }
...@@ -994,14 +969,10 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileChooserB ...@@ -994,14 +969,10 @@ JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileChooserB
HINSTANCE libComCtl32; HINSTANCE libComCtl32;
HINSTANCE libShell32; HINSTANCE libShell32;
libShell32 = LoadLibrary(TEXT("shell32.dll")); libShell32 = LoadLibrary(TEXT("shell32.dll"));
if (libShell32 != NULL) { if (libShell32 != NULL) {
long osVersion = GetVersion();
BOOL isVista = (!(osVersion & 0x80000000) && (LOBYTE(LOWORD(osVersion)) >= 6));
hBitmap = (HBITMAP)LoadImage(libShell32, 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); IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
} }
if (hBitmap == NULL) { if (hBitmap == NULL) {
...@@ -1095,46 +1066,6 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource ...@@ -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 * Helper function for creating Java column info object
*/ */
...@@ -1187,7 +1118,7 @@ JNIEXPORT jobjectArray JNICALL ...@@ -1187,7 +1118,7 @@ JNIEXPORT jobjectArray JNICALL
int colNum = -1; int colNum = -1;
hr = S_OK; hr = S_OK;
do{ do{
hr = GetDetailsOfFolder(pIShellFolder2, NULL, ++colNum, &sd); hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd);
} while (SUCCEEDED (hr)); } while (SUCCEEDED (hr));
jobjectArray columns = jobjectArray columns =
...@@ -1202,7 +1133,7 @@ JNIEXPORT jobjectArray JNICALL ...@@ -1202,7 +1133,7 @@ JNIEXPORT jobjectArray JNICALL
colNum = 0; colNum = 0;
hr = S_OK; hr = S_OK;
while (SUCCEEDED (hr)) { while (SUCCEEDED (hr)) {
hr = GetDetailsOfFolder(pIShellFolder2, NULL, colNum, &sd); hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd);
if (SUCCEEDED (hr)) { if (SUCCEEDED (hr)) {
hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags); hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags);
...@@ -1232,7 +1163,7 @@ JNIEXPORT jobjectArray JNICALL ...@@ -1232,7 +1163,7 @@ JNIEXPORT jobjectArray JNICALL
int colNum = -1; int colNum = -1;
hr = S_OK; hr = S_OK;
do{ do{
hr = GetDetailsOf(pIShellDetails, NULL, ++colNum, &sd); hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd);
} while (SUCCEEDED (hr)); } while (SUCCEEDED (hr));
jobjectArray columns = jobjectArray columns =
...@@ -1246,7 +1177,7 @@ JNIEXPORT jobjectArray JNICALL ...@@ -1246,7 +1177,7 @@ JNIEXPORT jobjectArray JNICALL
colNum = 0; colNum = 0;
hr = S_OK; hr = S_OK;
while (SUCCEEDED (hr)) { while (SUCCEEDED (hr)) {
hr = GetDetailsOf(pIShellDetails, NULL, colNum, &sd); hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd);
if (SUCCEEDED (hr)) { if (SUCCEEDED (hr)) {
jobject column = CreateColumnInfo(env, jobject column = CreateColumnInfo(env,
&columnClass, &columnConstructor, &columnClass, &columnConstructor,
...@@ -1288,7 +1219,7 @@ JNIEXPORT jobject JNICALL ...@@ -1288,7 +1219,7 @@ JNIEXPORT jobject JNICALL
if(SUCCEEDED (hr)) { if(SUCCEEDED (hr)) {
// The folder exposes IShellFolder2 interface // The folder exposes IShellFolder2 interface
IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown; IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
hr = GetDetailsOfFolder(pIShellFolder2, pidl, (UINT)columnIdx, &sd); hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
pIShellFolder2->Release(); pIShellFolder2->Release();
if (SUCCEEDED (hr)) { if (SUCCEEDED (hr)) {
STRRET strRet = sd.str; STRRET strRet = sd.str;
...@@ -1300,7 +1231,7 @@ JNIEXPORT jobject JNICALL ...@@ -1300,7 +1231,7 @@ JNIEXPORT jobject JNICALL
if(SUCCEEDED (hr)) { if(SUCCEEDED (hr)) {
// The folder exposes IShellDetails interface // The folder exposes IShellDetails interface
IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown; IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
hr = GetDetailsOf(pIShellDetails, pidl, (UINT)columnIdx, &sd); hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
pIShellDetails->Release(); pIShellDetails->Release();
if (SUCCEEDED (hr)) { if (SUCCEEDED (hr)) {
STRRET strRet = sd.str; STRRET strRet = sd.str;
......
/*
* @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.");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册