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