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