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