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