1 /*
   2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #define OEMRESOURCE
  27 
  28 #ifdef DEBUG
  29 // Warning : do not depend on anything in <awt.h>.  Including this file
  30 // is a fix for 4507525 to use the same operator new and delete as AWT.
  31 // This file should stand independent of AWT and should ultimately be
  32 // put into its own DLL.
  33 #include <awt.h>
  34 #else
  35 // Include jni_util.h first, so JNU_* macros can be redefined
  36 #include "jni_util.h"
  37 // Borrow some macros from awt.h
  38 #define JNU_NewStringPlatform(env, x) env->NewString(reinterpret_cast<jchar*>(x), static_cast<jsize>(_tcslen(x)))
  39 #define JNU_GetStringPlatformChars(env, x, y) reinterpret_cast<LPCWSTR>(env->GetStringChars(x, y))
  40 #define JNU_ReleaseStringPlatformChars(env, x, y) env->ReleaseStringChars(x, reinterpret_cast<const jchar*>(y))
  41 #endif // DEBUG
  42 
  43 #include <windows.h>
  44 #include <shlobj.h>
  45 #include <shellapi.h>
  46 #include "jlong.h"
  47 #include "alloc.h"
  48 
  49 #include "stdhdrs.h"
  50 
  51 // Copy from shlguid.h which is no longer in PlatformSDK
  52 #ifndef DEFINE_SHLGUID
  53 #define DEFINE_SHLGUID(name, l, w1, w2) DEFINE_GUID(name, l, w1, w2, 0xC0, 0, 0, 0, 0, 0, 0, 0x46)
  54 #endif
  55 
  56 // {93F2F68C-1D1B-11d3-A30E-00C04F79ABD1}
  57 DEFINE_GUID(IID_IShellFolder2, 0x93f2f68c, 0x1d1b, 0x11d3, 0xa3, 0xe, 0x0, 0xc0, 0x4f, 0x79, 0xab, 0xd1);
  58 
  59 #undef IID_IShellLinkW
  60 #undef IID_IExtractIconW
  61 // copied from shlguid.h
  62 DEFINE_SHLGUID(IID_IShellLinkW,         0x000214F9L, 0, 0);
  63 DEFINE_SHLGUID(IID_IExtractIconW,       0x000214FAL, 0, 0);
  64 
  65 //#include <sun_awt_shell_Win32ShellFolder2.h>
  66 
  67 #define DEFINE_FIELD_ID(var, cls, field, type)                            \
  68     jfieldID var = env->GetFieldID(cls, field, type);                     \
  69     DASSERT(var != NULL);                                                 \
  70     CHECK_NULL_RETURN(var, NULL);
  71 
  72 #define EXCEPTION_CHECK                                                   \
  73    if(env->ExceptionCheck()) {                                            \
  74         throw std::bad_alloc();                                           \
  75    }
  76 
  77 // Shell Functions
  78 typedef BOOL (WINAPI *DestroyIconType)(HICON);
  79 typedef HINSTANCE (WINAPI *FindExecutableType)(LPCTSTR,LPCTSTR,LPTSTR);
  80 typedef HICON (WINAPI *ImageList_GetIconType)(HIMAGELIST,int,UINT);
  81 typedef BOOL (WINAPI *GetIconInfoType)(HICON,PICONINFO);
  82 typedef HRESULT (WINAPI *SHGetDesktopFolderType)(IShellFolder**);
  83 typedef DWORD* (WINAPI *SHGetFileInfoType)(LPCTSTR,DWORD,SHFILEINFO*,UINT,UINT);
  84 typedef HRESULT (WINAPI *SHGetMallocType)(IMalloc**);
  85 typedef BOOL (WINAPI *SHGetPathFromIDListType)(LPCITEMIDLIST,LPTSTR);
  86 typedef HRESULT (WINAPI *SHGetSpecialFolderLocationType)(HWND,int,LPITEMIDLIST*);
  87 
  88 static DestroyIconType fn_DestroyIcon;
  89 static FindExecutableType fn_FindExecutable;
  90 static GetIconInfoType fn_GetIconInfo;
  91 static ImageList_GetIconType fn_ImageList_GetIcon;
  92 static SHGetDesktopFolderType fn_SHGetDesktopFolder;
  93 static SHGetFileInfoType fn_SHGetFileInfo;
  94 static SHGetMallocType fn_SHGetMalloc;
  95 static SHGetPathFromIDListType fn_SHGetPathFromIDList;
  96 static SHGetSpecialFolderLocationType fn_SHGetSpecialFolderLocation;
  97 
  98 // Field IDs
  99 static jmethodID MID_pIShellFolder;
 100 static jfieldID FID_pIShellIcon;
 101 static jmethodID MID_relativePIDL;
 102 static jfieldID FID_displayName;
 103 static jfieldID FID_folderType;
 104 
 105 // Other statics
 106 static IMalloc* pMalloc;
 107 static IShellFolder* pDesktop;
 108 
 109 // Some macros from awt.h, because it is not included in release
 110 #ifndef IS_WIN2000
 111 #define IS_WIN2000 (LOBYTE(LOWORD(::GetVersion())) >= 5)
 112 #endif
 113 #ifndef IS_WINXP
 114 #define IS_WINXP ((IS_WIN2000 && HIBYTE(LOWORD(::GetVersion())) >= 1) || LOBYTE(LOWORD(::GetVersion())) > 5)
 115 #endif
 116 #ifndef IS_WINVISTA
 117 #define IS_WINVISTA (!(::GetVersion() & 0x80000000) && LOBYTE(LOWORD(::GetVersion())) >= 6)
 118 #endif
 119 
 120 
 121 extern "C" {
 122 
 123 static BOOL initShellProcs()
 124 {
 125     static HMODULE libShell32 = NULL;
 126     static HMODULE libUser32 = NULL;
 127     static HMODULE libComCtl32 = NULL;
 128     // If already initialized, return TRUE
 129     if (libShell32 != NULL && libUser32 != NULL) {
 130         return TRUE;
 131     }
 132     // Load libraries
 133     libShell32 = JDK_LoadSystemLibrary("shell32.dll");
 134     if (libShell32 == NULL) {
 135         return FALSE;
 136     }
 137     libUser32 = JDK_LoadSystemLibrary("user32.dll");
 138     if (libUser32 == NULL) {
 139         return FALSE;
 140     }
 141     libComCtl32 = JDK_LoadSystemLibrary("comctl32.dll");
 142     if (libComCtl32 == NULL) {
 143         return FALSE;
 144     }
 145 
 146     // Set up procs - libComCtl32
 147     fn_ImageList_GetIcon = (ImageList_GetIconType)GetProcAddress(libComCtl32, "ImageList_GetIcon");
 148     if (fn_ImageList_GetIcon == NULL) {
 149         return FALSE;
 150     }
 151 
 152     // Set up procs - libShell32
 153         fn_FindExecutable = (FindExecutableType)GetProcAddress(
 154                 libShell32, "FindExecutableW");
 155     if (fn_FindExecutable == NULL) {
 156         return FALSE;
 157     }
 158         fn_SHGetDesktopFolder = (SHGetDesktopFolderType)GetProcAddress(libShell32,
 159                 "SHGetDesktopFolder");
 160     if (fn_SHGetDesktopFolder == NULL) {
 161         return FALSE;
 162     }
 163         fn_SHGetFileInfo = (SHGetFileInfoType)GetProcAddress(
 164                 libShell32, "SHGetFileInfoW");
 165     if (fn_SHGetFileInfo == NULL) {
 166         return FALSE;
 167     }
 168         fn_SHGetMalloc = (SHGetMallocType)GetProcAddress(libShell32,
 169         "SHGetMalloc");
 170     if (fn_SHGetMalloc == NULL) {
 171         return FALSE;
 172     }
 173     // Set up IMalloc
 174     if (fn_SHGetMalloc(&pMalloc) != S_OK) {
 175         return FALSE;
 176     }
 177         fn_SHGetPathFromIDList = (SHGetPathFromIDListType)GetProcAddress(
 178                 libShell32, "SHGetPathFromIDListW");
 179     if (fn_SHGetPathFromIDList == NULL) {
 180         return FALSE;
 181     }
 182         fn_SHGetSpecialFolderLocation = (SHGetSpecialFolderLocationType)
 183         GetProcAddress(libShell32, "SHGetSpecialFolderLocation");
 184     if (fn_SHGetSpecialFolderLocation == NULL) {
 185         return FALSE;
 186     }
 187 
 188     // Set up procs - libUser32
 189     fn_GetIconInfo = (GetIconInfoType)GetProcAddress(libUser32, "GetIconInfo");
 190     if (fn_GetIconInfo == NULL) {
 191         return FALSE;
 192     }
 193     fn_DestroyIcon = (DestroyIconType)GetProcAddress(libUser32, "DestroyIcon");
 194     if (fn_DestroyIcon == NULL) {
 195         return FALSE;
 196     }
 197     return TRUE;
 198 }
 199 
 200 // To call real JNU_NewStringPlatform
 201 #undef JNU_NewStringPlatform
 202 static jstring jstringFromSTRRET(JNIEnv* env, LPITEMIDLIST pidl, STRRET* pStrret) {
 203     switch (pStrret->uType) {
 204         case STRRET_CSTR :
 205             return JNU_NewStringPlatform(env, reinterpret_cast<const char*>(pStrret->cStr));
 206         case STRRET_OFFSET :
 207             // Note : this may need to be WCHAR instead
 208             return JNU_NewStringPlatform(env,
 209                                          (CHAR*)pidl + pStrret->uOffset);
 210         case STRRET_WSTR :
 211             return env->NewString(reinterpret_cast<const jchar*>(pStrret->pOleStr),
 212                 static_cast<jsize>(wcslen(pStrret->pOleStr)));
 213     }
 214     return NULL;
 215 }
 216 // restoring the original definition
 217 #define JNU_NewStringPlatform(env, x) env->NewString(reinterpret_cast<jchar*>(x), static_cast<jsize>(_tcslen(x)))
 218 
 219 /*
 220  * Class:     sun_awt_shell_Win32ShellFolder2
 221  * Method:    initIDs
 222  * Signature: ()V
 223  */
 224 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initIDs
 225     (JNIEnv* env, jclass cls)
 226 {
 227     if (!initShellProcs()) {
 228         JNU_ThrowInternalError(env, "Could not initialize shell library");
 229         return;
 230     }
 231     MID_pIShellFolder = env->GetMethodID(cls, "setIShellFolder", "(J)V");
 232     CHECK_NULL(MID_pIShellFolder);
 233     FID_pIShellIcon = env->GetFieldID(cls, "pIShellIcon", "J");
 234     CHECK_NULL(FID_pIShellIcon);
 235     MID_relativePIDL = env->GetMethodID(cls, "setRelativePIDL", "(J)V");
 236     CHECK_NULL(MID_relativePIDL);
 237     FID_displayName = env->GetFieldID(cls, "displayName", "Ljava/lang/String;");
 238     CHECK_NULL(FID_displayName);
 239     FID_folderType = env->GetFieldID(cls, "folderType", "Ljava/lang/String;");
 240     CHECK_NULL(FID_folderType);
 241 }
 242 
 243 
 244 /*
 245 * Class:     sun_awt_shell_Win32ShellFolderManager2
 246 * Method:    initializeCom
 247 * Signature: ()V
 248 */
 249 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_initializeCom
 250         (JNIEnv* env, jclass cls)
 251 {
 252     HRESULT hr = ::CoInitialize(NULL);
 253     if (FAILED(hr)) {
 254         char c[64];
 255         sprintf(c, "Could not initialize COM: HRESULT=0x%08X", hr);
 256         JNU_ThrowInternalError(env, c);
 257     }
 258 }
 259 
 260 /*
 261 * Class:     sun_awt_shell_Win32ShellFolderManager2
 262 * Method:    uninitializeCom
 263 * Signature: ()V
 264 */
 265 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom
 266         (JNIEnv* env, jclass cls)
 267 {
 268     ::CoUninitialize();
 269 }
 270 
 271 static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) {
 272     // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp
 273     HRESULT hres;
 274     IShellIcon* pIShellIcon;
 275     if (pIShellFolder != NULL) {
 276         hres = pIShellFolder->QueryInterface(IID_IShellIcon, (void**)&pIShellIcon);
 277         if (SUCCEEDED(hres)) {
 278             return pIShellIcon;
 279         }
 280     }
 281     return (IShellIcon*)NULL;
 282 }
 283 
 284 
 285 /*
 286  * Class:     sun_awt_shell_Win32ShellFolder2
 287  * Method:    getIShellIcon
 288  * Signature: (J)J
 289  */
 290 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIShellIcon
 291     (JNIEnv* env, jclass cls, jlong parentIShellFolder)
 292 {
 293     return (jlong)getIShellIcon((IShellFolder*)parentIShellFolder);
 294 }
 295 
 296 
 297 /*
 298  * Class:     sun_awt_shell_Win32ShellFolder2
 299  * Method:    initDesktop
 300  * Signature: ()V
 301  */
 302 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initDesktop
 303     (JNIEnv* env, jobject desktop)
 304 {
 305     // Get desktop IShellFolder
 306     HRESULT res = fn_SHGetDesktopFolder(&pDesktop);
 307     if (res != S_OK) {
 308         JNU_ThrowInternalError(env, "Could not get desktop shell folder");
 309         return;
 310     }
 311     // Set field ID for pIShellFolder
 312     env->CallVoidMethod(desktop, MID_pIShellFolder, (jlong)pDesktop);
 313     // Get desktop relative PIDL
 314     LPITEMIDLIST relPIDL;
 315     res = fn_SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &relPIDL);
 316     if (res != S_OK) {
 317         JNU_ThrowInternalError(env,
 318             "Could not get desktop shell folder ID list");
 319         return;
 320     }
 321     // Set field ID for relative PIDL
 322     env->CallVoidMethod(desktop, MID_relativePIDL, (jlong)relPIDL);
 323 }
 324 
 325 /*
 326  * Class:     sun_awt_shell_Win32ShellFolder2
 327  * Method:    initSpecial
 328  * Signature: (JI)V
 329  */
 330 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initSpecial
 331     (JNIEnv* env, jobject folder, jlong desktopIShellFolder, jint folderType)
 332 {
 333     // Get desktop IShellFolder interface
 334     IShellFolder* pDesktop = (IShellFolder*)desktopIShellFolder;
 335     if (pDesktop == NULL) {
 336         JNU_ThrowInternalError(env, "Desktop shell folder missing");
 337         return;
 338     }
 339     // Get special folder relative PIDL
 340     LPITEMIDLIST relPIDL;
 341     HRESULT res = fn_SHGetSpecialFolderLocation(NULL, folderType,
 342         &relPIDL);
 343     if (res != S_OK) {
 344         JNU_ThrowIOException(env, "Could not get shell folder ID list");
 345         return;
 346     }
 347     // Set field ID for relative PIDL
 348     env->CallVoidMethod(folder, MID_relativePIDL, (jlong)relPIDL);
 349     // Get special folder IShellFolder interface
 350     IShellFolder* pFolder;
 351     res = pDesktop->BindToObject(relPIDL, NULL, IID_IShellFolder,
 352         (void**)&pFolder);
 353     if (res != S_OK) {
 354         JNU_ThrowInternalError(env,
 355             "Could not bind shell folder to interface");
 356         return;
 357     }
 358     // Set field ID for pIShellFolder
 359     env->CallVoidMethod(folder, MID_pIShellFolder, (jlong)pFolder);
 360 }
 361 
 362 
 363 /*
 364  * Class:     sun_awt_shell_Win32ShellFolder2
 365  * Method:    getNextPIDLEntry
 366  * Signature: (J)J
 367  */
 368 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getNextPIDLEntry
 369     (JNIEnv* env, jclass cls, jlong jpIDL)
 370 {
 371     LPITEMIDLIST pIDL = (LPITEMIDLIST)jpIDL;
 372 
 373     // Check for valid pIDL.
 374     if(pIDL == NULL)
 375         return NULL;
 376 
 377     // Get the size of the specified item identifier.
 378     int cb = pIDL->mkid.cb;
 379 
 380     // If the size is zero, it is the end of the list.
 381     if (cb == 0)
 382         return NULL;
 383 
 384     // Add cb to pidl (casting to increment by bytes).
 385     pIDL = (LPITEMIDLIST)(((LPBYTE)pIDL) + cb);
 386 
 387     // Return NULL if it is null-terminating, or a pidl otherwise.
 388     return (pIDL->mkid.cb == 0) ? 0 : (jlong)pIDL;
 389 }
 390 
 391 
 392 /*
 393  * Class:     sun_awt_shell_Win32ShellFolder2
 394  * Method:    copyFirstPIDLEntry
 395  * Signature: (J)J
 396  */
 397 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_copyFirstPIDLEntry
 398     (JNIEnv* env, jclass cls, jlong jpIDL)
 399 {
 400     LPITEMIDLIST pIDL = (LPITEMIDLIST)jpIDL;
 401     if (pIDL == NULL) {
 402         return 0;
 403     }
 404     // Get the size of the specified item identifier.
 405     int cb = pIDL->mkid.cb;
 406 
 407     // If the size is zero, it is the end of the list.
 408     if (cb == 0)
 409         return 0;
 410 
 411     if (!IS_SAFE_SIZE_ADD(cb, sizeof(SHITEMID))) {
 412         return 0;
 413     }
 414     // Allocate space for this as well as null-terminating entry.
 415     LPITEMIDLIST newPIDL = (LPITEMIDLIST)pMalloc->Alloc(cb + sizeof(SHITEMID));
 416 
 417     // Copy data.
 418     memcpy(newPIDL, pIDL, cb);
 419 
 420     // Set null terminator for next entry.
 421     LPITEMIDLIST nextPIDL = (LPITEMIDLIST)(((LPBYTE)newPIDL) + cb);
 422     nextPIDL->mkid.cb = 0;
 423 
 424     return (jlong)newPIDL;
 425 }
 426 
 427 static int pidlLength(LPITEMIDLIST pIDL) {
 428     int len = 0;
 429     while (pIDL->mkid.cb != 0) {
 430         int cb = pIDL->mkid.cb;
 431         len += cb;
 432         pIDL = (LPITEMIDLIST)(((LPBYTE)pIDL) + cb);
 433     }
 434     return len;
 435 }
 436 
 437 /*
 438  * Class:     sun_awt_shell_Win32ShellFolder2
 439  * Method:    combinePIDLs
 440  * Signature: (J)J
 441  */
 442 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_combinePIDLs
 443     (JNIEnv* env, jclass cls, jlong jppIDL, jlong jpIDL)
 444 {
 445     // Combine an absolute (fully qualified) pidl in a parent with the relative
 446     // pidl of a child object to create a new absolute pidl for the child.
 447 
 448     LPITEMIDLIST parentPIDL   = (LPITEMIDLIST)jppIDL;
 449     LPITEMIDLIST relativePIDL = (LPITEMIDLIST)jpIDL;
 450 
 451     int len1 = pidlLength(parentPIDL);
 452     int len2 = pidlLength(relativePIDL);
 453 
 454     if (!IS_SAFE_SIZE_ADD(len1, len2) || !IS_SAFE_SIZE_ADD(len1 + len2, sizeof(SHITEMID))) {
 455         return 0;
 456     }
 457     LPITEMIDLIST newPIDL = (LPITEMIDLIST)pMalloc->Alloc(len1 + len2 + sizeof(SHITEMID));
 458     memcpy(newPIDL, parentPIDL, len1);
 459     memcpy(((LPBYTE) newPIDL) + len1, relativePIDL, len2);
 460     LPITEMIDLIST nullTerminator = (LPITEMIDLIST)(((LPBYTE) newPIDL) + len1 + len2);
 461     nullTerminator->mkid.cb = 0;
 462 
 463     return (jlong) newPIDL;
 464 }
 465 
 466 
 467 /*
 468  * Class:     sun_awt_shell_Win32ShellFolder2
 469  * Method:    releasePIDL
 470  * Signature: (J)V
 471  */
 472 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_releasePIDL
 473     (JNIEnv* env, jclass cls, jlong pIDL)
 474 {
 475     if (pIDL != 0L) {
 476         pMalloc->Free((LPITEMIDLIST)pIDL);
 477     }
 478 }
 479 
 480 
 481 /*
 482  * Class:     sun_awt_shell_Win32ShellFolder2
 483  * Method:    releaseIShellFolder
 484  * Signature: (J)V
 485  */
 486 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_releaseIShellFolder
 487     (JNIEnv* env, jclass cls, jlong pIShellFolder)
 488 {
 489     if (pIShellFolder != 0L) {
 490         ((IShellFolder*)pIShellFolder)->Release();
 491     }
 492 }
 493 
 494 
 495 /*
 496  * Class:     sun_awt_shell_Win32ShellFolder2
 497  * Method:    compareIDs
 498  * Signature: (JJJ)I
 499  */
 500 JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_compareIDs
 501     (JNIEnv* env, jclass cls, jlong jpParentIShellFolder, jlong pIDL1, jlong pIDL2)
 502 {
 503     IShellFolder* pParentIShellFolder = (IShellFolder*)jpParentIShellFolder;
 504     if (pParentIShellFolder == NULL) {
 505         return 0;
 506     }
 507     return pParentIShellFolder->CompareIDs(0, (LPCITEMIDLIST) pIDL1, (LPCITEMIDLIST) pIDL2);
 508 }
 509 
 510 
 511 /*
 512  * Class:     sun_awt_shell_Win32ShellFolder2
 513  * Method:    getAttributes0
 514  * Signature: (JJI)J
 515  */
 516 JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getAttributes0
 517     (JNIEnv* env, jclass cls, jlong jpParentIShellFolder, jlong jpIDL, jint attrsMask)
 518 {
 519     IShellFolder* pParentIShellFolder = (IShellFolder*)jpParentIShellFolder;
 520     if (pParentIShellFolder == NULL) {
 521         return 0;
 522     }
 523     LPCITEMIDLIST pIDL = (LPCITEMIDLIST)jpIDL;
 524     if (pIDL == NULL) {
 525         return 0;
 526     }
 527     ULONG attrs = attrsMask;
 528     HRESULT res = pParentIShellFolder->GetAttributesOf(1, &pIDL, &attrs);
 529     return attrs;
 530 }
 531 
 532 
 533 /*
 534  * Class:     sun_awt_shell_Win32ShellFolder2
 535  * Method:    getFileSystemPath0
 536  * Signature: (I)Ljava/lang/String;
 537  */
 538 JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath0
 539     (JNIEnv* env, jclass cls, jint csidl)
 540 {
 541     LPITEMIDLIST relPIDL;
 542     TCHAR szBuf[MAX_PATH];
 543     HRESULT res = fn_SHGetSpecialFolderLocation(NULL, csidl, &relPIDL);
 544     if (res != S_OK) {
 545         JNU_ThrowIOException(env, "Could not get shell folder ID list");
 546         return NULL;
 547     }
 548     if (fn_SHGetPathFromIDList(relPIDL, szBuf)) {
 549         return JNU_NewStringPlatform(env, szBuf);
 550     } else {
 551         return NULL;
 552     }
 553 }
 554 
 555 /*
 556  * Class:     sun_awt_shell_Win32ShellFolder2
 557  * Method:    getEnumObjects
 558  * Signature: (JZ)J
 559  */
 560 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getEnumObjects
 561     (JNIEnv* env, jobject folder, jlong pIShellFolder,
 562      jboolean isDesktop, jboolean includeHiddenFiles)
 563 {
 564     IShellFolder* pFolder = (IShellFolder*)pIShellFolder;
 565     if (pFolder == NULL) {
 566         return 0;
 567     }
 568     DWORD dwFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
 569     if (includeHiddenFiles) {
 570         dwFlags |= SHCONTF_INCLUDEHIDDEN;
 571     }
 572         /*
 573     if (!isDesktop) {
 574         dwFlags = dwFlags | SHCONTF_NONFOLDERS;
 575     }
 576         */
 577     IEnumIDList* pEnum;
 578     if (pFolder->EnumObjects(NULL, dwFlags, &pEnum) != S_OK) {
 579         return 0;
 580     }
 581     return (jlong)pEnum;
 582 }
 583 
 584 /*
 585  * Class:     sun_awt_shell_Win32ShellFolder2
 586  * Method:    getNextChild
 587  * Signature: (J)J
 588  */
 589 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getNextChild
 590     (JNIEnv* env, jobject folder, jlong pEnumObjects)
 591 {
 592     IEnumIDList* pEnum = (IEnumIDList*)pEnumObjects;
 593     if (pEnum == NULL) {
 594         return 0;
 595     }
 596     LPITEMIDLIST pidl;
 597     if (pEnum->Next(1, &pidl, NULL) != S_OK) {
 598         return 0;
 599     }
 600     return (jlong)pidl;
 601 }
 602 
 603 /*
 604  * Class:     sun_awt_shell_Win32ShellFolder2
 605  * Method:    releaseEnumObjects
 606  * Signature: (J)V
 607  */
 608 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_releaseEnumObjects
 609     (JNIEnv* env, jobject folder, jlong pEnumObjects)
 610 {
 611     IEnumIDList* pEnum = (IEnumIDList*)pEnumObjects;
 612     if (pEnum == NULL) {
 613         return;
 614     }
 615     pEnum->Release();
 616 }
 617 
 618 /*
 619  * Class:     sun_awt_shell_Win32ShellFolder2
 620  * Method:    bindToObject
 621  * Signature: (JJ)J
 622  */
 623 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_bindToObject
 624     (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL)
 625 {
 626     IShellFolder* pParent = (IShellFolder*)parentIShellFolder;
 627     if (pParent == NULL) {
 628         return 0;
 629     }
 630     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
 631     if (pidl == NULL) {
 632         return 0;
 633     }
 634     IShellFolder* pFolder;
 635     HRESULT hr = pParent->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pFolder);
 636     if (SUCCEEDED (hr)) {
 637         return (jlong)pFolder;
 638     }
 639     return 0;
 640 }
 641 
 642 
 643 /*
 644  * Class:     sun_awt_shell_Win32ShellFolder2
 645  * Method:    getLinkLocation
 646  * Signature: (JJZ)J;
 647  */
 648 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation
 649     (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jboolean resolve)
 650 {
 651     HRESULT hres;
 652     STRRET strret;
 653     OLECHAR olePath[MAX_PATH]; // wide-char version of path name
 654     LPWSTR wstr;
 655 
 656     IShellFolder* pParent = (IShellFolder*)parentIShellFolder;
 657     if (pParent == NULL) {
 658         return NULL;
 659     }
 660 
 661     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
 662     if (pidl == NULL) {
 663         return NULL;
 664     }
 665 
 666     hres = pParent->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &strret);
 667     if (FAILED(hres)) {
 668         return NULL;
 669     }
 670 
 671     switch (strret.uType) {
 672       case STRRET_CSTR :
 673         // IShellFolder::ParseDisplayName requires the path name in Unicode.
 674         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strret.cStr, -1, olePath, MAX_PATH);
 675         wstr = olePath;
 676         break;
 677 
 678       case STRRET_OFFSET :
 679         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (CHAR *)pidl + strret.uOffset, -1, olePath, MAX_PATH);
 680         wstr = olePath;
 681         break;
 682 
 683       case STRRET_WSTR :
 684         wstr = strret.pOleStr;
 685         break;
 686     }
 687 
 688     IShellLinkW* psl;
 689     hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID *)&psl);
 690     if (SUCCEEDED(hres)) {
 691         IPersistFile* ppf;
 692         hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
 693         if (SUCCEEDED(hres)) {
 694             hres = ppf->Load(wstr, STGM_READ);
 695             if (SUCCEEDED(hres)) {
 696                 if (resolve) {
 697                     hres = psl->Resolve(NULL, 0);
 698                     // Ignore failure
 699                 }
 700                 pidl = (LPITEMIDLIST)NULL;
 701                 hres = psl->GetIDList(&pidl);
 702             }
 703             ppf->Release();
 704         }
 705         psl->Release();
 706     }
 707 
 708     if (strret.uType == STRRET_WSTR) {
 709         CoTaskMemFree(strret.pOleStr);
 710     }
 711     if (SUCCEEDED(hres)) {
 712         return (jlong)pidl;
 713     } else {
 714         return 0;
 715     }
 716 }
 717 
 718 
 719 /*
 720  * Class:     sun_awt_shell_Win32ShellFolder2
 721  * Method:    parseDisplayName0
 722  * Signature: (JLjava/lang/String;)J
 723  */
 724 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0
 725     (JNIEnv* env, jclass cls, jlong jpIShellFolder, jstring jname)
 726 {
 727 
 728     // Get desktop IShellFolder interface
 729     IShellFolder* pIShellFolder = (IShellFolder*)jpIShellFolder;
 730     if (pIShellFolder == NULL) {
 731         JNU_ThrowInternalError(env, "Desktop shell folder missing");
 732         return 0;
 733     }
 734     // Get relative PIDL for name
 735     LPITEMIDLIST pIDL;
 736     int nLength = env->GetStringLength(jname);
 737     const jchar* strPath = env->GetStringChars(jname, NULL);
 738     JNU_CHECK_EXCEPTION_RETURN(env, 0);
 739     jchar* wszPath = new jchar[nLength + 1];
 740     wcsncpy(reinterpret_cast<LPWSTR>(wszPath), reinterpret_cast<LPCWSTR>(strPath), nLength);
 741     wszPath[nLength] = 0;
 742     HRESULT res = pIShellFolder->ParseDisplayName(NULL, NULL,
 743                         reinterpret_cast<LPWSTR>(wszPath), NULL, &pIDL, NULL);
 744     if (res != S_OK) {
 745         JNU_ThrowIOException(env, "Could not parse name");
 746         pIDL = 0;
 747     }
 748     delete[] wszPath;
 749     env->ReleaseStringChars(jname, strPath);
 750     return (jlong)pIDL;
 751 }
 752 
 753 
 754 /*
 755  * Class:     sun_awt_shell_Win32ShellFolder2
 756  * Method:    getDisplayNameOf
 757  * Signature: (JJI)Ljava/lang/String;
 758  */
 759 JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf
 760     (JNIEnv* env, jclass cls, jlong parentIShellFolder, jlong relativePIDL, jint attrs)
 761 {
 762     IShellFolder* pParent = (IShellFolder*)parentIShellFolder;
 763     if (pParent == NULL) {
 764         return NULL;
 765     }
 766     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
 767     if (pidl == NULL) {
 768         return NULL;
 769     }
 770     STRRET strret;
 771     if (pParent->GetDisplayNameOf(pidl, attrs, &strret) != S_OK) {
 772         return NULL;
 773     }
 774     jstring result = jstringFromSTRRET(env, pidl, &strret);
 775     if (strret.uType == STRRET_WSTR) {
 776         CoTaskMemFree(strret.pOleStr);
 777     }
 778     return result;
 779 }
 780 
 781 /*
 782  * Class:     sun_awt_shell_Win32ShellFolder2
 783  * Method:    getFolderType
 784  * Signature: (J)Ljava/lang/String;
 785  */
 786 JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFolderType
 787     (JNIEnv* env, jclass cls, jlong pIDL)
 788 {
 789     SHFILEINFO fileInfo;
 790     if (fn_SHGetFileInfo((LPCTSTR)pIDL, 0L, &fileInfo, sizeof(fileInfo),
 791         SHGFI_TYPENAME | SHGFI_PIDL) == 0) {
 792         return NULL;
 793     }
 794     return JNU_NewStringPlatform(env, fileInfo.szTypeName);
 795 }
 796 
 797 /*
 798  * Class:     sun_awt_shell_Win32ShellFolder2
 799  * Method:    getExecutableType
 800  * Signature: (Ljava/lang/String;)Ljava/lang/String;
 801  */
 802 JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getExecutableType
 803     (JNIEnv* env, jobject folder, jstring path)
 804 {
 805     TCHAR szBuf[MAX_PATH];
 806     LPCTSTR szPath = JNU_GetStringPlatformChars(env, path, NULL);
 807     if (szPath == NULL) {
 808         return NULL;
 809     }
 810     HINSTANCE res = fn_FindExecutable(szPath, szPath, szBuf);
 811     JNU_ReleaseStringPlatformChars(env, path, szPath);
 812     if ((UINT_PTR)res < 32) {
 813         return NULL;
 814     }
 815     return JNU_NewStringPlatform(env, szBuf);
 816 }
 817 
 818 
 819 /*
 820  * Class:     sun_awt_shell_Win32ShellFolder2
 821  * Method:    getIcon
 822  * Signature: (Ljava/lang/String;Z)J
 823  */
 824 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIcon
 825     (JNIEnv* env, jclass cls, jstring absolutePath, jboolean getLargeIcon)
 826 {
 827     HICON hIcon = NULL;
 828     SHFILEINFO fileInfo;
 829     LPCTSTR pathStr = JNU_GetStringPlatformChars(env, absolutePath, NULL);
 830     JNU_CHECK_EXCEPTION_RETURN(env, 0);
 831     if (fn_SHGetFileInfo(pathStr, 0L, &fileInfo, sizeof(fileInfo),
 832                          SHGFI_ICON | (getLargeIcon ? 0 : SHGFI_SMALLICON)) != 0) {
 833         hIcon = fileInfo.hIcon;
 834     }
 835     JNU_ReleaseStringPlatformChars(env, absolutePath, pathStr);
 836     return (jlong)hIcon;
 837 }
 838 
 839 /*
 840  * Class:     sun_awt_shell_Win32ShellFolder2
 841  * Method:    getIconIndex
 842  * Signature: (JJ)I
 843  */
 844 JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex
 845     (JNIEnv* env, jclass cls, jlong pIShellIconL, jlong relativePIDL)
 846 {
 847     IShellIcon* pIShellIcon = (IShellIcon*)pIShellIconL;
 848     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
 849     if (pIShellIcon == NULL && pidl == NULL) {
 850         return 0;
 851     }
 852 
 853     INT index = -1;
 854 
 855     HRESULT hres;
 856     // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp
 857     if (pIShellIcon != NULL) {
 858         hres = pIShellIcon->GetIconOf(pidl, GIL_FORSHELL, &index);
 859     }
 860 
 861     return (jint)index;
 862 }
 863 
 864 
 865 /*
 866  * Class:     sun_awt_shell_Win32ShellFolder2
 867  * Method:    extractIcon
 868  * Signature: (JJZZ)J
 869  */
 870 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
 871     (JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL,
 872                                 jboolean getLargeIcon, jboolean getDefaultIcon)
 873 {
 874     IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
 875     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
 876     if (pIShellFolder == NULL || pidl == NULL) {
 877         return 0;
 878     }
 879 
 880     HICON hIcon = NULL;
 881 
 882     HRESULT hres;
 883     IExtractIconW* pIcon;
 884     hres = pIShellFolder->GetUIObjectOf(NULL, 1, const_cast<LPCITEMIDLIST*>(&pidl),
 885                                         IID_IExtractIconW, NULL, (void**)&pIcon);
 886     if (SUCCEEDED(hres)) {
 887         WCHAR szBuf[MAX_PATH];
 888         INT index;
 889         UINT flags;
 890         UINT uFlags = getDefaultIcon ? GIL_DEFAULTICON : GIL_FORSHELL | GIL_ASYNC;
 891         hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
 892         if (SUCCEEDED(hres)) {
 893             HICON hIconLarge;
 894             hres = pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32);
 895             if (SUCCEEDED(hres)) {
 896                 if (getLargeIcon) {
 897                     fn_DestroyIcon((HICON)hIcon);
 898                     hIcon = hIconLarge;
 899                 } else {
 900                     fn_DestroyIcon((HICON)hIconLarge);
 901                 }
 902             }
 903         } else if (hres == E_PENDING) {
 904             pIcon->Release();
 905             return E_PENDING;
 906         }
 907         pIcon->Release();
 908     }
 909     return (jlong)hIcon;
 910 }
 911 
 912 
 913 /*
 914  * Class:     sun_awt_shell_Win32ShellFolder2
 915  * Method:    disposeIcon
 916  * Signature: (J)V
 917  */
 918 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_disposeIcon
 919     (JNIEnv* env, jclass cls, jlong hicon)
 920 {
 921     fn_DestroyIcon((HICON)hicon);
 922 }
 923 
 924 /*
 925  * Class:     sun_awt_shell_Win32ShellFolder2
 926  * Method:    getIconBits
 927  * Signature: (JI)[I
 928  */
 929 JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
 930     (JNIEnv* env, jclass cls, jlong hicon, jint iconSize)
 931 {
 932     jintArray iconBits = NULL;
 933 
 934     // Get the icon info
 935     ICONINFO iconInfo;
 936     if (fn_GetIconInfo((HICON)hicon, &iconInfo)) {
 937         // Get the screen DC
 938         HDC dc = GetDC(NULL);
 939         if (dc != NULL) {
 940             // Set up BITMAPINFO
 941             BITMAPINFO bmi;
 942             memset(&bmi, 0, sizeof(BITMAPINFO));
 943             bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 944             bmi.bmiHeader.biWidth = iconSize;
 945             bmi.bmiHeader.biHeight = -iconSize;
 946             bmi.bmiHeader.biPlanes = 1;
 947             bmi.bmiHeader.biBitCount = 32;
 948             bmi.bmiHeader.biCompression = BI_RGB;
 949             // Extract the color bitmap
 950             int nBits = iconSize * iconSize;
 951             long colorBits[1024];
 952             GetDIBits(dc, iconInfo.hbmColor, 0, iconSize, colorBits, &bmi, DIB_RGB_COLORS);
 953             // XP supports alpha in some icons, and depending on device.
 954             // This should take precedence over the icon mask bits.
 955             BOOL hasAlpha = FALSE;
 956             if (IS_WINXP) {
 957                 for (int i = 0; i < nBits; i++) {
 958                     if ((colorBits[i] & 0xff000000) != 0) {
 959                         hasAlpha = TRUE;
 960                         break;
 961                     }
 962                 }
 963             }
 964             if (!hasAlpha) {
 965                 // Extract the mask bitmap
 966                 long maskBits[1024];
 967                 GetDIBits(dc, iconInfo.hbmMask, 0, iconSize, maskBits, &bmi, DIB_RGB_COLORS);
 968                 // Copy the mask alphas into the color bits
 969                 for (int i = 0; i < nBits; i++) {
 970                     if (maskBits[i] == 0) {
 971                         colorBits[i] |= 0xff000000;
 972                     }
 973                 }
 974             }
 975             // Release DC
 976             ReleaseDC(NULL, dc);
 977             // Create java array
 978             iconBits = env->NewIntArray(nBits);
 979             if (!(env->ExceptionCheck())) {
 980             // Copy values to java array
 981             env->SetIntArrayRegion(iconBits, 0, nBits, colorBits);
 982         }
 983         }
 984         // Fix 4745575 GDI Resource Leak
 985         // MSDN
 986         // GetIconInfo creates bitmaps for the hbmMask and hbmColor members of ICONINFO.
 987         // The calling application must manage these bitmaps and delete them when they
 988         // are no longer necessary.
 989         ::DeleteObject(iconInfo.hbmColor);
 990         ::DeleteObject(iconInfo.hbmMask);
 991     }
 992     return iconBits;
 993 }
 994 
 995 /*
 996  * Class:     sun_awt_shell_Win32ShellFolder2
 997  * Method:    getStandardViewButton0
 998  * Signature: (I)[I
 999  */
1000 JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardViewButton0
1001     (JNIEnv* env, jclass cls, jint iconIndex)
1002 {
1003     jintArray result = NULL;
1004 
1005     // Create a toolbar
1006     HWND hWndToolbar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
1007         0, 0, 0, 0, 0,
1008         NULL, NULL, NULL, NULL);
1009 
1010     if (hWndToolbar != NULL) {
1011         SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_VIEW_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
1012 
1013         HIMAGELIST hImageList = (HIMAGELIST) SendMessage(hWndToolbar, TB_GETIMAGELIST, 0, 0);
1014 
1015         if (hImageList != NULL) {
1016             HICON hIcon = ImageList_GetIcon(hImageList, iconIndex, ILD_TRANSPARENT);
1017 
1018             if (hIcon != NULL) {
1019                 result = Java_sun_awt_shell_Win32ShellFolder2_getIconBits(env, cls, ptr_to_jlong(hIcon), 16);
1020 
1021                 DestroyIcon(hIcon);
1022             }
1023 
1024             ImageList_Destroy(hImageList);
1025         }
1026 
1027         DestroyWindow(hWndToolbar);
1028     }
1029 
1030     return result;
1031 }
1032 
1033 /*
1034  * Class:     sun_awt_shell_Win32ShellFolder2
1035  * Method:    getSystemIcon
1036  * Signature: (I)J
1037  */
1038 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getSystemIcon
1039     (JNIEnv* env, jclass cls, jint iconID)
1040 {
1041     return (jlong)LoadIcon(NULL, MAKEINTRESOURCE(iconID));
1042 }
1043 
1044 
1045 /*
1046  * Class:     sun_awt_shell_Win32ShellFolder2
1047  * Method:    getIconResource
1048  * Signature: (Ljava/lang/String;IIIZ)J
1049  */
1050 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource
1051     (JNIEnv* env, jclass cls, jstring libName, jint iconID,
1052      jint cxDesired, jint cyDesired, jboolean useVGAColors)
1053 {
1054     const char *pLibName = env->GetStringUTFChars(libName, NULL);
1055     JNU_CHECK_EXCEPTION_RETURN(env, 0);
1056     HINSTANCE libHandle = (HINSTANCE)JDK_LoadSystemLibrary(pLibName);
1057     if (libHandle != NULL) {
1058         UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0;
1059         return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID),
1060                                       IMAGE_ICON, cxDesired, cyDesired,
1061                                       fuLoad));
1062     }
1063     return 0;
1064 }
1065 
1066 
1067 /*
1068  * Helper function for creating Java column info object
1069  */
1070 static jobject CreateColumnInfo(JNIEnv *pEnv,
1071                                 jclass *pClass, jmethodID *pConstructor,
1072                                 SHELLDETAILS *psd, ULONG visible)
1073 {
1074     jstring str = jstringFromSTRRET(pEnv, NULL, &(psd->str));
1075     JNU_CHECK_EXCEPTION_RETURN(pEnv, NULL);
1076 
1077     return pEnv->NewObject(*pClass, *pConstructor,
1078                     str,
1079                     (jint)(psd->cxChar * 6), // TODO: is 6 OK for converting chars to pixels?
1080                     (jint)psd->fmt, (jboolean) visible);
1081 }
1082 
1083 
1084 /*
1085  * Class:     sun_awt_shell_Win32ShellFolder2
1086  * Method:    doGetColumnInfo
1087  * Signature: (J)[Lsun/awt/shell/ShellFolderColumnInfo;
1088  */
1089 JNIEXPORT jobjectArray JNICALL
1090     Java_sun_awt_shell_Win32ShellFolder2_doGetColumnInfo
1091             (JNIEnv *env, jobject obj, jlong iShellFolder)
1092 {
1093 
1094     HRESULT hr;
1095     IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1096     IUnknown *pIUnknown = NULL;
1097 
1098     jclass columnClass = env->FindClass("sun/awt/shell/ShellFolderColumnInfo");
1099     if(NULL == columnClass) {
1100         return NULL;
1101     }
1102 
1103     jmethodID columnConstructor =
1104         env->GetMethodID(columnClass, "<init>", "(Ljava/lang/String;IIZ)V");
1105     if(NULL == columnConstructor) {
1106         return NULL;
1107     }
1108 
1109     // We'are asking the object the list of available columns
1110     SHELLDETAILS sd;
1111 
1112     hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1113     if(SUCCEEDED (hr)) {
1114 
1115         // The folder exposes IShellFolder2 interface
1116         IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1117 
1118         // Count columns
1119         int colNum = -1;
1120         hr = S_OK;
1121         do{
1122             hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd);
1123         } while (SUCCEEDED (hr));
1124 
1125         jobjectArray columns =
1126             env->NewObjectArray((jsize) colNum, columnClass, NULL);
1127         if(NULL == columns) {
1128             pIShellFolder2->Release();
1129             return NULL;
1130         }
1131 
1132         // Fill column details list
1133         SHCOLSTATEF csFlags;
1134         colNum = 0;
1135         hr = S_OK;
1136         while (SUCCEEDED (hr)) {
1137             hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd);
1138 
1139             if (SUCCEEDED (hr)) {
1140                 hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags);
1141                 if (SUCCEEDED (hr)) {
1142                     if(!(csFlags & SHCOLSTATE_HIDDEN)) {
1143                         jobject column = CreateColumnInfo(env,
1144                                             &columnClass, &columnConstructor,
1145                                             &sd, csFlags & SHCOLSTATE_ONBYDEFAULT);
1146                         if(!column){
1147                             pIShellFolder2->Release();
1148                             return NULL;
1149                         }
1150                         env->SetObjectArrayElement(columns, (jsize) colNum, column);
1151                     }
1152                 }
1153                 colNum++;
1154             }
1155         }
1156 
1157         pIShellFolder2->Release();
1158 
1159         return columns;
1160     }
1161 
1162     hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1163     if(SUCCEEDED (hr)) {
1164         // The folder exposes IShellDetails interface
1165         IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1166 
1167         // Count columns
1168         int colNum = -1;
1169         hr = S_OK;
1170         do{
1171             hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd);
1172         } while (SUCCEEDED (hr));
1173 
1174         jobjectArray columns =
1175             env->NewObjectArray((jsize) colNum, columnClass, NULL);
1176         if(NULL == columns) {
1177             pIShellDetails->Release();
1178             return NULL;
1179         }
1180 
1181         // Fill column details list
1182         colNum = 0;
1183         hr = S_OK;
1184         while (SUCCEEDED (hr)) {
1185             hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd);
1186             if (SUCCEEDED (hr)) {
1187                 jobject column = CreateColumnInfo(env,
1188                                     &columnClass, &columnConstructor,
1189                                     &sd, 1);
1190                 if(!column){
1191                     pIShellDetails->Release();
1192                     return NULL;
1193                 }
1194                 env->SetObjectArrayElement(columns, (jsize) colNum++, column);
1195             }
1196         }
1197 
1198         pIShellDetails->Release();
1199 
1200         return columns;
1201     }
1202 
1203     // The folder exposes neither IShellFolder2 nor IShelDetails
1204     return NULL;
1205 
1206 }
1207 
1208 /*
1209  * Class:     sun_awt_shell_Win32ShellFolder2
1210  * Method:    doGetColumnValue
1211  * Signature: (JJI)Ljava/lang/Object;
1212  */
1213 JNIEXPORT jobject JNICALL
1214     Java_sun_awt_shell_Win32ShellFolder2_doGetColumnValue
1215             (JNIEnv *env, jobject obj, jlong iShellFolder,
1216             jlong jpidl, jint columnIdx)
1217 {
1218 
1219     HRESULT hr;
1220     IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1221     IUnknown *pIUnknown = NULL;
1222 
1223 
1224     LPITEMIDLIST pidl = (LPITEMIDLIST) jpidl;
1225     SHELLDETAILS sd;
1226 
1227     hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1228     if(SUCCEEDED (hr)) {
1229         // The folder exposes IShellFolder2 interface
1230         IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1231         hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1232         pIShellFolder2->Release();
1233         if (SUCCEEDED (hr)) {
1234             STRRET strRet = sd.str;
1235             return jstringFromSTRRET(env, pidl, &strRet);
1236         }
1237     }
1238 
1239     hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1240     if(SUCCEEDED (hr)) {
1241         // The folder exposes IShellDetails interface
1242         IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1243         hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1244         pIShellDetails->Release();
1245         if (SUCCEEDED (hr)) {
1246             STRRET strRet = sd.str;
1247             return jstringFromSTRRET(env, pidl, &strRet);
1248         }
1249     }
1250 
1251     // The folder exposes neither IShellFolder2 nor IShelDetails
1252     return NULL;
1253 }
1254 
1255 /*
1256  * Class:     sun_awt_shell_Win32ShellFolder2
1257  * Method:    compareIDsByColumn
1258  * Signature: (JJJI)I
1259  */
1260 JNIEXPORT jint JNICALL
1261     Java_sun_awt_shell_Win32ShellFolder2_compareIDsByColumn
1262             (JNIEnv* env, jclass cls, jlong jpParentIShellFolder,
1263             jlong pIDL1, jlong pIDL2, jint columnIdx)
1264 {
1265     IShellFolder* pParentIShellFolder = (IShellFolder*)jpParentIShellFolder;
1266     if (pParentIShellFolder == NULL) {
1267         return 0;
1268     }
1269 
1270     HRESULT hr = pParentIShellFolder->CompareIDs(
1271                                             (UINT) columnIdx,
1272                                             (LPCITEMIDLIST) pIDL1,
1273                                             (LPCITEMIDLIST) pIDL2);
1274     if (SUCCEEDED (hr)) {
1275         return (jint) (short) HRESULT_CODE(hr);
1276     }
1277 
1278     return 0;
1279 }
1280 
1281 /*
1282  * Class:     sun_awt_shell_Win32ShellFolder2
1283  * Method:    loadKnownFolders
1284  * Signature: (V)[BLsun/awt/shell/Win32ShellFolder2$KnownfolderDefenition;
1285  */
1286 JNIEXPORT jobjectArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders
1287     (JNIEnv* env, jclass cls )
1288 {
1289     IKnownFolderManager* pkfm = NULL;
1290     HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL,
1291                                 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm));
1292     if (!SUCCEEDED(hr)) return NULL;
1293 
1294     TRY;
1295 
1296     jclass cl = env->FindClass("sun/awt/shell/Win32ShellFolder2$KnownFolderDefinition");
1297     CHECK_NULL_RETURN(cl, NULL);
1298     DEFINE_FIELD_ID(field_guid, cl, "guid", "Ljava/lang/String;")
1299     DEFINE_FIELD_ID(field_name, cl, "name", "Ljava/lang/String;");
1300     DEFINE_FIELD_ID(field_description, cl, "description", "Ljava/lang/String;");
1301     DEFINE_FIELD_ID(field_parent, cl, "parent", "Ljava/lang/String;");
1302     DEFINE_FIELD_ID(field_relativePath, cl, "relativePath", "Ljava/lang/String;");
1303     DEFINE_FIELD_ID(field_parsingName, cl, "parsingName", "Ljava/lang/String;");
1304     DEFINE_FIELD_ID(field_tooltip, cl, "tooltip", "Ljava/lang/String;");
1305     DEFINE_FIELD_ID(field_localizedName, cl, "localizedName", "Ljava/lang/String;");
1306     DEFINE_FIELD_ID(field_icon, cl, "icon", "Ljava/lang/String;");
1307     DEFINE_FIELD_ID(field_security, cl, "security", "Ljava/lang/String;");
1308     DEFINE_FIELD_ID(field_path, cl, "path", "Ljava/lang/String;");
1309     DEFINE_FIELD_ID(field_saveLocation, cl, "saveLocation", "Ljava/lang/String;");
1310     DEFINE_FIELD_ID(field_category, cl, "category", "I");
1311     DEFINE_FIELD_ID(field_attributes, cl, "attributes", "J");
1312     DEFINE_FIELD_ID(field_defenitionFlags, cl, "defenitionFlags", "I");
1313     DEFINE_FIELD_ID(field_ftidType, cl, "ftidType", "Ljava/lang/String;");
1314 
1315     jobjectArray result;
1316     KNOWNFOLDERID* pFoldersIds = NULL;
1317     UINT count = 0;
1318     if (SUCCEEDED(pkfm->GetFolderIds(&pFoldersIds, &count))) {
1319         jmethodID initMethod;
1320         try {
1321             result = env->NewObjectArray(count, cl, NULL);
1322             initMethod = env->GetMethodID(cl, "<init>", "()V");
1323             EXCEPTION_CHECK
1324         } catch (std::bad_alloc&) {
1325             CoTaskMemFree(pFoldersIds);
1326             pkfm->Release();
1327             throw;
1328         }
1329         for(UINT i = 0; i < count; ++i)
1330         {
1331             jobject fld;
1332             const KNOWNFOLDERID& folderId = pFoldersIds[i];
1333             LPOLESTR guid = NULL;
1334             try {
1335                 fld = env->NewObject(cl, initMethod);
1336                 if (fld) {
1337                     env->SetObjectArrayElement(result, i, fld);
1338                 }
1339                 EXCEPTION_CHECK
1340 
1341                 if (SUCCEEDED(StringFromCLSID(folderId, &guid))) {
1342                     jstring jstr = JNU_NewStringPlatform(env, guid);
1343                     if (jstr) {
1344                         env->SetObjectField(fld, field_guid, jstr);
1345                     }
1346                     CoTaskMemFree(guid);
1347                     EXCEPTION_CHECK
1348                 }
1349             } catch (std::bad_alloc&) {
1350                 CoTaskMemFree(pFoldersIds);
1351                 pkfm->Release();
1352                 throw;
1353             }
1354 
1355             IKnownFolder* pFolder = NULL;
1356             if (SUCCEEDED(pkfm->GetFolder(folderId, &pFolder))) {
1357                 KNOWNFOLDER_DEFINITION kfDef;
1358                 if (SUCCEEDED(pFolder->GetFolderDefinition(&kfDef)))
1359                 {
1360                     try {
1361                         jstring jstr = JNU_NewStringPlatform(env, kfDef.pszName);
1362                         if(jstr) {
1363                             env->SetObjectField(fld, field_name, jstr);
1364                         }
1365                         EXCEPTION_CHECK
1366                         if (kfDef.pszDescription) {
1367                             jstr = JNU_NewStringPlatform(env, kfDef.pszDescription);
1368                             if (jstr) {
1369                                 env->SetObjectField(fld, field_description, jstr);
1370                             }
1371                             EXCEPTION_CHECK
1372                         }
1373                         EXCEPTION_CHECK
1374                         if (SUCCEEDED(StringFromCLSID(kfDef.fidParent, &guid))) {
1375                             jstr = JNU_NewStringPlatform(env, guid);
1376                             if (jstr) {
1377                                 env->SetObjectField(fld, field_parent, jstr);
1378                             }
1379                             CoTaskMemFree(guid);
1380                             EXCEPTION_CHECK
1381                         }
1382                         if (kfDef.pszRelativePath) {
1383                             jstr = JNU_NewStringPlatform(env, kfDef.pszRelativePath);
1384                             if (jstr) {
1385                                 env->SetObjectField(fld, field_relativePath, jstr);
1386                             }
1387                             EXCEPTION_CHECK
1388                         }
1389                         if (kfDef.pszParsingName) {
1390                             jstr = JNU_NewStringPlatform(env, kfDef.pszParsingName);
1391                             if (jstr) {
1392                                 env->SetObjectField(fld, field_parsingName, jstr);
1393                             }
1394                             EXCEPTION_CHECK
1395                         }
1396                         if (kfDef.pszTooltip) {
1397                             jstr = JNU_NewStringPlatform(env, kfDef.pszTooltip);
1398                             if (jstr) {
1399                                 env->SetObjectField(fld, field_tooltip, jstr);
1400                             }
1401                             EXCEPTION_CHECK
1402                         }
1403                         if (kfDef.pszLocalizedName) {
1404                             jstr = JNU_NewStringPlatform(env, kfDef.pszLocalizedName);
1405                             if (jstr) {
1406                                 env->SetObjectField(fld, field_localizedName, jstr);
1407                             }
1408                             EXCEPTION_CHECK
1409                         }
1410                         if (kfDef.pszIcon) {
1411                             jstr = JNU_NewStringPlatform(env, kfDef.pszIcon);
1412                             if (jstr) {
1413                                 env->SetObjectField(fld, field_icon, jstr);
1414                             }
1415                             EXCEPTION_CHECK
1416                         }
1417                         if (kfDef.pszSecurity) {
1418                             jstr = JNU_NewStringPlatform(env, kfDef.pszSecurity);
1419                             if (jstr) {
1420                                 env->SetObjectField(fld, field_security, jstr);
1421                             }
1422                             EXCEPTION_CHECK
1423                         }
1424                         if (SUCCEEDED(StringFromCLSID(kfDef.ftidType, &guid))) {
1425                             jstr = JNU_NewStringPlatform(env, guid);
1426                             if (jstr) {
1427                                 env->SetObjectField(fld, field_ftidType, jstr);
1428                             }
1429                             CoTaskMemFree(guid);
1430                             EXCEPTION_CHECK
1431                         }
1432                         env->SetIntField(fld, field_category, kfDef.category);
1433                         env->SetIntField(fld, field_defenitionFlags, kfDef.kfdFlags);
1434                         env->SetLongField(fld, field_attributes, kfDef.dwAttributes);
1435 
1436                         LPWSTR folderPath = NULL;
1437                         if (SUCCEEDED(pFolder->GetPath(KF_FLAG_NO_ALIAS, &folderPath))
1438                                     && folderPath) {
1439                             jstr = JNU_NewStringPlatform(env, folderPath);
1440                             if (jstr) {
1441                                 env->SetObjectField(fld, field_path, jstr);
1442                             }
1443                             CoTaskMemFree(folderPath);
1444                             EXCEPTION_CHECK
1445                         }
1446 
1447                         IShellLibrary *plib = NULL;
1448                         hr = CoCreateInstance(CLSID_ShellLibrary, NULL,
1449                                          CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&plib));
1450                         if (SUCCEEDED(hr)) {
1451                             hr = plib->LoadLibraryFromKnownFolder(folderId, STGM_READWRITE);
1452                             if (SUCCEEDED(hr)) {
1453                                 IShellItem *item = NULL;
1454                                 hr = plib->GetDefaultSaveFolder(DSFT_DETECT,
1455                                         IID_PPV_ARGS(&item));
1456                                 if (SUCCEEDED(hr) && item) {
1457                                     LPWSTR loc = NULL;
1458                                     hr = item->GetDisplayName(SIGDN_FILESYSPATH, &loc);
1459                                     if (SUCCEEDED(hr) && loc)
1460                                     {
1461                                         jstr = JNU_NewStringPlatform(env, loc);
1462                                         if (jstr) {
1463                                             env->SetObjectField(fld, field_saveLocation, jstr);
1464                                         }
1465                                         CoTaskMemFree(loc);
1466                                     }
1467                                     item->Release();
1468                                 }
1469                             }
1470                             plib->Release();
1471                             EXCEPTION_CHECK
1472                         }
1473                         FreeKnownFolderDefinitionFields(&kfDef);
1474                     } catch (std::bad_alloc&) {
1475                         FreeKnownFolderDefinitionFields(&kfDef);
1476                         pFolder->Release();
1477                         CoTaskMemFree(pFoldersIds);
1478                         pkfm->Release();
1479                         throw;
1480                     }
1481                 }
1482             }
1483             pFolder->Release();
1484         }
1485         CoTaskMemFree(pFoldersIds);
1486     }
1487     pkfm->Release();
1488     return result;
1489     CATCH_BAD_ALLOC_RET(NULL);
1490 }
1491 
1492 } // extern "C"