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