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