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