--- old/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2015-05-20 17:05:23.190955900 +0300 +++ new/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2015-05-20 17:05:22.622342200 +0300 @@ -163,6 +163,27 @@ } } + // Known Folder data + static class KnownFolderDefinition { + String guid; + int category; + String name; + String description; + String parent; + String relativePath; + String parsingName; + String tooltip; + String localizedName; + String icon; + String security; + long attributes; + int defenitionFlags; + String ftidType; + String path; + String saveLocation; + static final List libraries = getLibraries(); + } + static class FolderDisposer implements sun.java2d.DisposerRecord { /* * This is cached as a concession to getFolderType(), which needs @@ -578,7 +599,22 @@ return s; } } - return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING); + String path = getDisplayNameOf(parentIShellFolder, relativePIDL, + SHGDN_FORPARSING); + // if this is a library its default save location is taken as a path + // this is a temp fix until java.io starts support Libraries + if( path != null && path.startsWith("::{") && + path.toLowerCase().endsWith(".library-ms")) { + for (KnownFolderDefinition kf : KnownFolderDefinition.libraries) { + if( path.toLowerCase().endsWith( + kf.relativePath.toLowerCase()) && + path.toUpperCase().startsWith( + kf.parsingName.substring(0, 40).toUpperCase()) ) { + return kf.saveLocation; + } + } + } + return path; } // Needs to be accessible to Win32ShellFolderManager2 @@ -848,6 +884,9 @@ long relativePIDL, int attrs); + // Returns data of all Known Folders registered in the system + private static native KnownFolderDefinition[] loadKnownFolders(); + /** * @return The name used to display this shell folder */ @@ -1178,4 +1217,26 @@ return result == null ? 0 : result; } } + + // Extracts libraries and their default save locations from Known Folders list + private static List getLibraries() { + return invoke(new Callable>() { + @Override + public List call() throws Exception { + KnownFolderDefinition[] all = loadKnownFolders(); + List folders = new ArrayList<>(); + if (all != null) { + for (KnownFolderDefinition kf : all) { + if (kf.relativePath == null || kf.parsingName == null || + kf.saveLocation == null) { + continue; + } + folders.add(kf); + } + } + return folders; + } + }); + } + } --- old/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp 2015-05-20 17:05:26.194056400 +0300 +++ new/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp 2015-05-20 17:05:25.633944400 +0300 @@ -64,6 +64,11 @@ //#include +#define DEFINE_FIELD_ID(var, cls, field, type) \ + jfieldID var = env->GetFieldID(cls, field, type); \ + DASSERT(var != NULL); \ + CHECK_NULL_RETURN(var, NULL); + // Shell Functions typedef BOOL (WINAPI *DestroyIconType)(HICON); typedef HINSTANCE (WINAPI *FindExecutableType)(LPCTSTR,LPCTSTR,LPTSTR); @@ -1263,5 +1268,142 @@ return 0; } +/* + * Class: sun_awt_shell_Win32ShellFolder2 + * Method: loadKnownFolders + * Signature: (V)[BLsun/awt/shell/Win32ShellFolder2$KnownfolderDefenition; + */ +JNIEXPORT jobjectArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders + (JNIEnv* env, jclass cls ) +{ + CoInitialize(NULL); + IKnownFolderManager* pkfm = NULL; + HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm)); + if(!SUCCEEDED(hr)) return NULL; + + TRY; + + jclass cl = env->FindClass("sun/awt/shell/Win32ShellFolder2$KnownFolderDefinition"); + CHECK_NULL_RETURN(cl, NULL); + DEFINE_FIELD_ID(field_guid, cl, "guid", "Ljava/lang/String;") + DEFINE_FIELD_ID(field_name, cl, "name", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_description, cl, "description", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_parent, cl, "parent", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_relativePath, cl, "relativePath", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_parsingName, cl, "parsingName", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_tooltip, cl, "tooltip", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_localizedName, cl, "localizedName", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_icon, cl, "icon", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_security, cl, "security", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_path, cl, "path", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_saveLocation, cl, "saveLocation", "Ljava/lang/String;"); + DEFINE_FIELD_ID(field_category, cl, "category", "I"); + DEFINE_FIELD_ID(field_attributes, cl, "attributes", "J"); + DEFINE_FIELD_ID(field_defenitionFlags, cl, "defenitionFlags", "I"); + DEFINE_FIELD_ID(field_ftidType, cl, "ftidType", "Ljava/lang/String;"); + + jobjectArray result; + KNOWNFOLDERID* pFoldersIds = NULL; + UINT count = 0; + if(SUCCEEDED(pkfm->GetFolderIds(&pFoldersIds, &count))) { + result = env->NewObjectArray(count, cl, NULL); + jmethodID initMethod = env->GetMethodID(cl, "", "()V"); + for(UINT i = 0; i < count; ++i) + { + jobject fld = env->NewObject(cl, initMethod); + env->SetObjectArrayElement(result, i, fld); + + const KNOWNFOLDERID& folderId = pFoldersIds[i]; + LPOLESTR guid = NULL; + if(SUCCEEDED(StringFromCLSID(folderId, &guid))) { + env->SetObjectField(fld, field_guid, JNU_NewStringPlatform(env, guid)); + CoTaskMemFree(guid); + } + + IKnownFolder* pFolder = NULL; + if(SUCCEEDED(pkfm->GetFolder(folderId, &pFolder))) { + KNOWNFOLDER_DEFINITION kfDef; + if(SUCCEEDED(pFolder->GetFolderDefinition(&kfDef))) + { + env->SetObjectField(fld, field_name, + JNU_NewStringPlatform(env, kfDef.pszName)); + if(kfDef.pszDescription) + env->SetObjectField(fld, field_description, + JNU_NewStringPlatform(env, kfDef.pszDescription)); + if(SUCCEEDED(StringFromCLSID(kfDef.fidParent, &guid))) { + env->SetObjectField(fld, field_parent, + JNU_NewStringPlatform(env, guid)); + CoTaskMemFree(guid); + } + if(kfDef.pszRelativePath) + env->SetObjectField(fld, field_relativePath, + JNU_NewStringPlatform(env, kfDef.pszRelativePath)); + if(kfDef.pszParsingName) + env->SetObjectField(fld, field_parsingName, + JNU_NewStringPlatform(env, kfDef.pszParsingName)); + if(kfDef.pszTooltip) + env->SetObjectField(fld, field_tooltip, + JNU_NewStringPlatform(env, kfDef.pszTooltip)); + if(kfDef.pszLocalizedName) + env->SetObjectField(fld, field_localizedName, + JNU_NewStringPlatform(env, kfDef.pszLocalizedName)); + if(kfDef.pszIcon) + env->SetObjectField(fld, field_icon, + JNU_NewStringPlatform(env, kfDef.pszIcon)); + if(kfDef.pszSecurity) + env->SetObjectField(fld, field_security, + JNU_NewStringPlatform(env, kfDef.pszSecurity)); + if(SUCCEEDED(StringFromCLSID(kfDef.ftidType, &guid))) { + env->SetObjectField(fld, field_ftidType, + JNU_NewStringPlatform(env, guid)); + CoTaskMemFree(guid); + } + env->SetIntField(fld, field_category, kfDef.category); + env->SetIntField(fld, field_defenitionFlags, kfDef.kfdFlags); + env->SetLongField(fld, field_attributes, kfDef.dwAttributes); + FreeKnownFolderDefinitionFields(&kfDef); + + LPWSTR folderPath = NULL; + if(SUCCEEDED(pFolder->GetPath(KF_FLAG_NO_ALIAS, &folderPath)) + && folderPath) { + env->SetObjectField(fld, field_path, + JNU_NewStringPlatform(env, folderPath)); + CoTaskMemFree(folderPath); + } + + IShellLibrary *plib = NULL; + hr = CoCreateInstance(CLSID_ShellLibrary, NULL, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&plib)); + if(SUCCEEDED(hr)) { + hr = plib->LoadLibraryFromKnownFolder(folderId, STGM_READWRITE); + if(SUCCEEDED(hr)) { + IShellItem *item = NULL; + hr = plib->GetDefaultSaveFolder(DSFT_DETECT, + IID_PPV_ARGS(&item)); + if(SUCCEEDED(hr) && item) { + LPWSTR loc = NULL; + hr = item->GetDisplayName(SIGDN_FILESYSPATH, &loc); + if(SUCCEEDED(hr) && loc) + { + env->SetObjectField(fld, field_saveLocation, + JNU_NewStringPlatform(env, loc)); + CoTaskMemFree(loc); + } + item->Release(); + } + } + plib->Release(); + } + } + } + pFolder->Release(); + } + CoTaskMemFree(pFoldersIds); + } + pkfm->Release(); + return result; + CATCH_BAD_ALLOC_RET(NULL); +} } // extern "C" --- /dev/null 2015-05-20 17:05:29.000000000 +0300 +++ new/test/java/awt/FileDialog/8003399/bug8003399.java 2015-05-20 17:05:28.390995700 +0300 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8003399 + @summary JFileChooser gives wrong path to selected file when saving to Libraries folder on Windows 7 + @author Semyon Sadetsky + @library /lib/testlibrary + @build jdk.testlibrary.OSInfo + @run main bug8003399 + */ + +import jdk.testlibrary.OSInfo; + +import javax.swing.filechooser.FileSystemView; +import java.io.File; + +public class bug8003399 { + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS && + OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_VISTA) > 0 ) { + FileSystemView fsv = FileSystemView.getFileSystemView(); + for (File file : fsv.getFiles(fsv.getHomeDirectory(), false)) { + if(file.isDirectory()) { + for (File file1 : fsv.getFiles(file, false)) { + if(file1.isDirectory()) + { + String path = file1.getPath(); + if(path.startsWith("::{") && + path.toLowerCase().endsWith(".library-ms")) { + throw new RuntimeException("Unconverted library link found"); + } + } + } + } + } + } + System.out.println("ok"); + } +}