6491795: COM should be initialized for Shell API calls in ShellFolder2.cpp
Reviewed-by: peterz, loneid
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java Thu Mar 12 14:00:26 2009 +0300
@@ -27,6 +27,7 @@
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 @@
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<DoChangeContents>() {
+ public DoChangeContents call() throws Exception {
+ FileSystemView fileSystem = filechooser.getFileSystemView();
- File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
+ File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
- Vector<File> acceptsList = new Vector<File>();
+ Vector<File> acceptsList = new Vector<File>();
- 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);
+ // First sort alphabetically by filename
+ sort(acceptsList);
- Vector<File> newDirectories = new Vector<File>(50);
- Vector<File> newFiles = new Vector<File>();
- // 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;
- }
- }
+ Vector<File> newDirectories = new Vector<File>(50);
+ Vector<File> newFiles = new Vector<File>();
+ // 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<File> newFileCache = new Vector<File>(newDirectories);
- newFileCache.addAll(newFiles);
+ Vector<File> newFileCache = new Vector<File>(newDirectories);
+ newFileCache.addAll(newFiles);
- int newSize = newFileCache.size();
- int oldSize = fileCache.size();
+ 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;
+ 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 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
- && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) {
- if(isInterrupted()) {
- return;
+ if (!fileCache.equals(newFileCache)) {
+ if (isInterrupted()) {
+ cancelRunnables(runnables);
+ }
+ return new DoChangeContents(newFileCache, 0, fileCache, 0, fid);
}
- invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid));
- newFileCache = null;
+ return 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
- && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) {
- if(isInterrupted()) {
- return;
- }
- invokeLater(new DoChangeContents(null, 0, new Vector<File>(fileCache.subList(start, end)),
- start, fid));
- newFileCache = null;
- }
- }
- if (newFileCache != null && !fileCache.equals(newFileCache)) {
- if (isInterrupted()) {
- cancelRunnables(runnables);
- }
- invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid));
+ });
+
+ if (doChangeContents != null) {
+ runnables.addElement(doChangeContents);
+ SwingUtilities.invokeLater(doChangeContents);
}
}
--- a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java Thu Mar 12 14:00:26 2009 +0300
@@ -31,6 +31,7 @@
import java.io.*;
import java.io.FileNotFoundException;
import java.util.*;
+import java.util.concurrent.Callable;
/**
* @author Michael Martak
@@ -461,6 +462,35 @@
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
*/
--- a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java Thu Mar 12 14:00:26 2009 +0300
@@ -27,6 +27,7 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.concurrent.Callable;
/**
* @author Michael Martak
@@ -96,9 +97,23 @@
}
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> T invoke(Callable<T> task) {
+ try {
+ return task.call();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
--- a/jdk/src/share/classes/sun/swing/FilePane.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/share/classes/sun/swing/FilePane.java Thu Mar 12 14:00:26 2009 +0300
@@ -34,6 +34,7 @@
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 @@
}
}
+ @Override
+ public void sort() {
+ ShellFolder.getInvoker().invoke(new Callable<Void>() {
+ public Void call() throws Exception {
+ DetailsTableRowSorter.super.sort();
+ return null;
+ }
+ });
+ }
+
public void modelStructureChanged() {
super.modelStructureChanged();
updateComparators(detailsTableModel.getColumns());
--- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java Thu Mar 12 14:00:26 2009 +0300
@@ -32,6 +32,7 @@
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 @@
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<Void>() {
+ 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 @@
*/
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<Void>() {
+ public Void call() throws Exception {
+ 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;
+ }
+ } else {
+ break;
+ }
}
- } else {
- break;
}
+ return null;
}
- }
+ });
sun.java2d.Disposer.addRecord(this, disposer);
}
@@ -281,17 +296,26 @@
/**
* 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<String>() {
+ 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 @@
* 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<File>() {
+ 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 @@
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 @@
*/
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<Long>() {
+ 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 @@
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<Boolean>() {
+ 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<Boolean>() {
+ 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 @@
* 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) {
+ 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;
+ 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;
+ 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<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.
// Path is assumed to be non-null
@@ -557,24 +630,33 @@
*/
// 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<Long>() {
+ 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 @@
* object. The array will be empty if the folder is empty. Returns
* <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();
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<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
- long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles);
- if (pEnumObjects != 0) {
- long childPIDL;
- int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
- do {
- if (Thread.currentThread().isInterrupted()) {
+ return ShellFolder.getInvoker().invoke(new Callable<File[]>() {
+ public File[] call() throws Exception {
+ 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];
}
- 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);
+
+ 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<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
+ 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);
}
- if (releasePIDL) {
- releasePIDL(childPIDL);
- }
- } 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 @@
*
* @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;
+ Win32ShellFolder2 getChildByPath(final String filePath) {
+ return ShellFolder.getInvoker().invoke(new Callable<Win32ShellFolder2>() {
+ 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(this, childIShellFolder, childPIDL, path);
- break;
+ 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 @@
// 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 @@
return getLinkLocation(true);
}
- private ShellFolder getLinkLocation(boolean resolve) {
- if (!isLink()) {
- return null;
- }
+ private ShellFolder getLinkLocation(final boolean resolve) {
+ return ShellFolder.getInvoker().invoke(new Callable<ShellFolder>() {
+ 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<Long>() {
+ 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 @@
*/
public String getDisplayName() {
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 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 @@
*/
public String getFolderType() {
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;
}
@@ -774,11 +898,16 @@
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 @@
private long getIShellIcon() {
if (pIShellIcon == -1L) {
- pIShellIcon = getIShellIcon(getIShellFolder());
+ pIShellIcon =
+ ShellFolder.getInvoker().invoke(new Callable<Long>() {
+ public Long call() throws Exception {
+ return getIShellIcon(getIShellFolder());
+ }
+ });
}
return pIShellIcon;
}
@@ -850,50 +984,60 @@
/**
* @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();
+ 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();
- 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;
+ // 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 (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;
}
- 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);
- }
- }
- }
- }
-
- if (icon == null) {
- // These are only cached per object
- long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon);
- icon = makeIcon(hIcon, getLargeIcon);
- disposeIcon(hIcon);
- }
-
+ });
if (getLargeIcon) {
largeIcon = icon;
} else {
smallIcon = icon;
}
}
- if (icon == null) {
- icon = super.getIcon(getLargeIcon);
- }
return icon;
}
@@ -969,39 +1113,50 @@
private static final int LVCFMT_CENTER = 2;
public ShellFolderColumnInfo[] getFolderColumns() {
- ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
+ return ShellFolder.getInvoker().invoke(new Callable<ShellFolderColumnInfo[]>() {
+ public ShellFolderColumnInfo[] call() throws Exception {
+ ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
- if (columns != null) {
- List<ShellFolderColumnInfo> notNullColumns =
- new ArrayList<ShellFolderColumnInfo>();
- 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);
+ if (columns != null) {
+ List<ShellFolderColumnInfo> notNullColumns =
+ new ArrayList<ShellFolderColumnInfo>();
+ 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));
+ column.setComparator(new ColumnComparator(getIShellFolder(), i));
- notNullColumns.add(column);
+ 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<Object>() {
+ 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 @@
}
// 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<Integer>() {
+ 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;
+ }
+ });
}
}
-
}
--- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Thu Mar 12 14:00:26 2009 +0300
@@ -31,7 +31,10 @@
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 @@
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();
}
--- a/jdk/src/windows/native/sun/windows/ShellFolder2.cpp Thu Feb 26 11:44:43 2009 +0300
+++ b/jdk/src/windows/native/sun/windows/ShellFolder2.cpp Thu Mar 12 14:00:26 2009 +0300
@@ -225,6 +225,34 @@
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 @@
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 @@
/*
* 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 @@
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 @@
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 @@
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 @@
}
psl->Release();
}
- if (doCoUninit) {
- ::CoUninitialize();
- }
if (SUCCEEDED(hres)) {
return (jlong)pidl;
@@ -741,7 +730,7 @@
/*
* 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 @@
}
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 @@
hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index);
}
- if (doCoUninit) {
- ::CoUninitialize();
- }
return (jint)index;
}
@@ -866,10 +848,6 @@
}
HICON hIcon = NULL;
- BOOL doCoUninit;
- if (!CoInit(doCoUninit)) {
- return (jlong)hIcon;
- }
HRESULT hres;
IExtractIconW* pIcon;
@@ -894,9 +872,6 @@
}
pIcon->Release();
}
- if (doCoUninit) {
- ::CoUninitialize();
- }
return (jlong)hIcon;
}
@@ -994,14 +969,10 @@
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 @@
}
-// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFileChooser/6570445/bug6570445.java Thu Mar 12 14:00:26 2009 +0300
@@ -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.");
+ }
+}