/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// NOTE: This class supersedes Win32ShellFolder, which was removed from
// distribution after version 1.4.2.
/**
* Win32 Shell Folders
* <P>
* <BR>
* There are two fundamental types of shell folders : file system folders
* and non-file system folders. File system folders are relatively easy
* to deal with. Non-file system folders are items such as My Computer,
* Network Neighborhood, and the desktop. Some of these non-file system
* folders have special values and properties.
* <P>
* <BR>
* Win32 keeps two basic data structures for shell folders. The first
* of these is called an ITEMIDLIST. Usually a pointer, called an
* LPITEMIDLIST, or more frequently just "PIDL". This structure holds
* a series of identifiers and can be either relative to the desktop
* (an absolute PIDL), or relative to the shell folder that contains them.
* Some Win32 functions can take absolute or relative PIDL values, and
* others can only accept relative values.
* <BR>
* The second data structure is an IShellFolder COM interface. Using
* this interface, one can enumerate the relative PIDLs in a shell
* folder, get attributes, etc.
* <BR>
* All Win32ShellFolder2 objects which are folder types (even non-file
* system folders) contain an IShellFolder object. Files are named in
* directories via relative PIDLs.
*
* @author Michael Martak
* @author Leif Samuelsson
* @author Kenneth Russell
* @since 1.4 */
private static native void initIDs();
static {
initIDs();
}
// Win32 Shell Folder Constants
// Win32 shell folder attributes
// IShellFolder::GetDisplayNameOf constants
// Values for system call LoadIcon()
public enum SystemIcon {
private final int iconID;
}
public int getIconID() {
return iconID;
}
}
/*
* This is cached as a concession to getFolderType(), which needs
* an absolute PIDL.
*/
long absolutePIDL;
/*
* We keep track of shell folders through the IShellFolder
* interface of their parents plus their relative PIDL.
*/
long pIShellFolder;
long relativePIDL;
boolean disposed;
public void dispose() {
if (disposed) return;
if (relativePIDL != 0) {
}
if (absolutePIDL != 0) {
}
if (pIShellFolder != 0) {
}
return null;
}
});
disposed = true;
}
}
}
}
/*
* The following are for caching various shell folder properties.
*/
/*
* The following is to identify the My Documents folder as being special
*/
private boolean isPersonal;
: path;
}
/**
* Create a system special shell folder, such as the
* desktop or Network Neighborhood.
*/
// Desktop is parent of DRIVES and NETWORK, not necessarily
// other special shell folders.
initDesktop();
} else {
// 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.
parent = getDesktop();
while (pIDL != 0) {
// Get a child pidl relative to 'parent'
if (childPIDL != 0) {
// Get a handle to the the rest of the ID list
// i,e, parent's grandchilren and down
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'.
} else {
// No grandchildren means we have arrived at the parent of 'this',
// and childPIDL is directly relative to parent.
}
} else {
break;
}
}
}
return null;
}
}, InterruptedException.class);
}
/**
* Create a system shell folder
*/
}
/**
* Creates a shell folder with a parent and relative PIDL
*/
Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) throws InterruptedException {
super(parent,
}
}, RuntimeException.class)
);
}
// 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
/** Marks this folder as being the My Documents (Personal) folder */
public void setIsPersonal() {
isPersonal = true;
}
/**
* This method is implemented to make sure that no instances
* of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns
* <code>true</code>, then the object is representable with an instance of
* <code>java.io.File</code> instead. If not, then the object depends
* on native PIDL state and should not be serialized.
*
* @return a <code>java.io.File</code> replacement object. If the folder
* is a not a normal directory, then returns the first non-removable
* drive (normally "C:\").
*/
if (isFileSystem()) {
} else {
if (driveRoots != null) {
if (driveRoots[i] instanceof Win32ShellFolder2) {
}
}
}
}
}
// Ouch, we have no hard drives. Return something "valid" anyway.
return new File("C:\\");
}
}
});
}
/**
* Finalizer to clean up any COM objects or PIDLs used by this object.
*/
protected void dispose() {
}
// Given a (possibly multi-level) relative PIDL (with respect to
// the desktop, at least in all of the usage cases in this code),
// return a pointer to the next entry. Does not mutate the PIDL in
// any way. Returns 0 if the null terminator is reached.
// Needs to be accessible to Win32ShellFolderManager2
// Given a (possibly multi-level) relative PIDL (with respect to
// the desktop, at least in all of the usage cases in this code),
// copy the first entry into a newly-allocated PIDL. Returns 0 if
// the PIDL is at the end of the list.
// Needs to be accessible to Win32ShellFolderManager2
// Given a parent's absolute PIDL and our relative PIDL, build an absolute PIDL
// Release a PIDL object
// Needs to be accessible to Win32ShellFolderManager2
// Release an IShellFolder object
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
/**
* Accessor for IShellFolder
*/
private long getIShellFolder() {
try {
assert(isDirectory());
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.
if (pIShellFolder == 0) {
throw new InternalError("Unable to bind "
+ getAbsolutePath() + " to parent");
}
return pIShellFolder;
}
}, RuntimeException.class);
} catch (InterruptedException e) {
// Ignore error
}
}
return disposer.pIShellFolder;
}
/**
* Get the parent ShellFolder's IShellFolder interface
*/
public long getParentIShellFolder() {
// Parent should only be null if this is the desktop, whose
// relativePIDL is relative to its own IShellFolder.
return getIShellFolder();
}
return parent.getIShellFolder();
}
/**
* Accessor for relative PIDL
*/
public long getRelativePIDL() {
throw new InternalError("Should always have a relative PIDL");
}
return disposer.relativePIDL;
}
private long getAbsolutePIDL() {
// This is the desktop
return getRelativePIDL();
} else {
disposer.absolutePIDL = combinePIDLs(((Win32ShellFolder2)parent).getAbsolutePIDL(), getRelativePIDL());
}
return disposer.absolutePIDL;
}
}
/**
* Helper function to return the desktop
*/
return Win32ShellFolderManager2.getDesktop();
}
/**
* Helper function to return the desktop IShellFolder interface
*/
public long getDesktopIShellFolder() {
return getDesktop().getIShellFolder();
}
// Same effective implementation as Win32FileSystem
}
/**
* Check to see if two ShellFolder objects are the same
*/
if (o == null || !(o instanceof Win32ShellFolder2)) {
// Short-circuit circuitous delegation path
if (!(o instanceof File)) {
return super.equals(o);
}
}
return false;
}
// Only folders with identical parents can be equal
}
try {
} catch (InterruptedException e) {
return false;
}
}
return false;
}
throws InterruptedException {
}
}, RuntimeException.class);
}
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
/**
* @return Whether this is a file system shell folder
*/
public boolean isFileSystem() {
if (cachedIsFileSystem == null) {
}
return cachedIsFileSystem;
}
/**
* Return whether the given attribute flag is set for this object
*/
// Caching at this point doesn't seem to be cost efficient
return (getAttributes0(getParentIShellFolder(),
& attribute) != 0;
}
});
}
/**
* Returns the queried attributes specified in attrsMask.
*
* 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
*/
// Return the path to the underlying file system object
// Should be called from the COM thread
String s =
return s;
}
}
}
// Needs to be accessible to Win32ShellFolderManager2
return getFileSystemPath0(csidl);
}
}, IOException.class);
}
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// Return whether the path is a network root.
// Path is assumed to be non-null
}
/**
* @return The parent shell folder of this shell folder, null if
* there is no parent
*/
return parent;
}
public boolean isDirectory() {
// Folders with SFGAO_BROWSABLE have "shell extension" handlers and are
// not traversable in JFileChooser.
} else if (isLink()) {
} else {
}
}
return isDir.booleanValue();
}
/*
* Functions for enumerating an IShellFolder's children
*/
// Returns an IEnumIDList interface for an IShellFolder. The value
// returned must be released using releaseEnumObjects().
}
}, RuntimeException.class);
}
// 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
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
// Releases the IEnumIDList interface
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// 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
/**
* @return An array of shell folders that are children of this shell folder
* object. The array will be empty if the folder is empty. Returns
* <code>null</code> if this shellfolder does not denote a directory.
*/
}
try {
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!
return new File[0];
}
// 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.
if (pEnumObjects != 0) {
try {
long childPIDL;
do {
boolean releasePIDL = true;
if (childPIDL != 0 &&
} else {
releasePIDL = false;
}
}
if (releasePIDL) {
}
} finally {
}
}
? new File[0]
}
}, InterruptedException.class);
} catch (InterruptedException e) {
return new File[0];
}
}
/**
* Look for (possibly special) child folder by it's path
*
* @return The child shellfolder, or null if not found.
*/
long pIShellFolder = getIShellFolder();
long pEnumObjects = getEnumObjects(true);
long childPIDL;
break;
}
}
}
return child;
}
}, InterruptedException.class);
}
/**
* @return Whether this shell folder is a link
*/
public boolean isLink() {
if (cachedIsLink == null) {
}
return cachedIsLink;
}
/**
* @return Whether this shell folder is marked as hidden
*/
public boolean isHidden() {
return hasAttribute(ATTRIB_HIDDEN);
}
// 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
long relativePIDL, boolean resolve);
/**
* @return The shell folder linked to by this shell folder, or null
* if this shell folder is not a link or is a broken or invalid link
*/
return getLinkLocation(true);
}
public ShellFolder call() {
if (!isLink()) {
return null;
}
getRelativePIDL(), resolve);
if (linkLocationPIDL != 0) {
try {
location =
} catch (InterruptedException e) {
// Return null
} 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;
}
});
}
// Parse a display name into a PIDL relative to the current IShellFolder.
}
}, IOException.class);
}
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// 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
long relativePIDL,
int attrs);
/**
* @return The name used to display this shell folder
*/
if (displayName == null) {
return getDisplayNameOf(getParentIShellFolder(),
}
});
}
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
/**
* @return The type of shell folder as a string
*/
if (folderType == null) {
final long absolutePIDL = getAbsolutePIDL();
return getFolderType(absolutePIDL);
}
});
}
return folderType;
}
// Return the executable type of a file system shell folder
/**
* @return The executable type as a string
*/
if (!isFileSystem()) {
return null;
}
return getExecutableType(getAbsolutePath());
}
// Icons
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// Return the icon of a file system shell folder in the form of an HICON
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
boolean getLargeIcon);
// Returns an icon from the Windows system icon list in the form of an HICON
boolean useVGAColors);
// Note: useVGAColors is ignored on XP and later
// Return the bits from an HICON. This has a side effect of setting
// the imageHash variable for efficient caching / comparing.
// Dispose the HICON
// Should be called from the COM thread
private long getIShellIcon() {
if (pIShellIcon == -1L) {
}
return pIShellIcon;
}
// Get the bits. This has the side effect of setting the imageHash value for this object.
return img;
}
}
return null;
}
/**
* @return The icon image used to display this shell folder
*/
icon =
if (isFileSystem()) {
: 0L;
long relativePIDL = getRelativePIDL();
// These are cached per type (using the index in the system image list)
if (index > 0) {
if (isLink()) {
} else {
}
}
}
}
}
// These are only cached per object
}
}
return newIcon;
}
});
if (getLargeIcon) {
} else {
}
}
return icon;
}
/**
* Gets an icon from the Windows system icon list as an <code>Image</code>
*/
return icon;
}
/**
* Gets an icon from the Windows system icon list as an <code>Image</code>
*/
boolean useVGAColors = true; // Will be ignored on XP and later
if (shellIconBPP != null) {
}
if (hIcon != 0) {
return icon;
}
return null;
}
/**
* Returns the canonical form of this abstract pathname. Equivalent to
* <code>new Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
*
* @see java.io.File#getCanonicalFile
*/
return this;
}
/*
* Indicates whether this is a special folder (includes My Documents)
*/
public boolean isSpecial() {
}
/**
* Compares this object with the specified object for order.
*
* @see sun.awt.shell.ShellFolder#compareTo(File)
*/
if (!(file2 instanceof Win32ShellFolder2)) {
if (isFileSystem() && !isSpecial()) {
} else {
return -1; // Non-file shellfolders sort before files
}
}
}
// native constants from commctrl.h
public ShellFolderColumnInfo[] call() {
new ArrayList<ShellFolderColumnInfo>();
}
}
}
return columns;
}
});
}
}
});
}
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
// 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);
// To avoid loads of synchronizations with Invoker and improve performance we
// synchronize the whole code of the sort method once
return null;
}
});
}
private final int columnIdx;
this.shellFolder = shellFolder;
}
// compares 2 objects within this folder by the specified column
if (o instanceof Win32ShellFolder2
&& o1 instanceof Win32ShellFolder2) {
// delegates comparison to native method
((Win32ShellFolder2) o).getRelativePIDL(),
}
return 0;
}
});
}
}
}