1 /*
2  * Copyright (c) 2003, 2021, 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 
initShellProcs()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
jstringFromSTRRET(JNIEnv * env,LPITEMIDLIST pidl,STRRET * pStrret)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  */
Java_sun_awt_shell_Win32ShellFolder2_initIDs(JNIEnv * env,jclass cls)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 */
Java_sun_awt_shell_Win32ShellFolderManager2_initializeCom(JNIEnv * env,jclass cls)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 */
Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom(JNIEnv * env,jclass cls)313 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom
314         (JNIEnv* env, jclass cls)
315 {
316     ::CoUninitialize();
317 }
318 
getIShellIcon(IShellFolder * pIShellFolder)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  */
Java_sun_awt_shell_Win32ShellFolder2_getIShellIcon(JNIEnv * env,jclass cls,jlong parentIShellFolder)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  */
Java_sun_awt_shell_Win32ShellFolder2_initDesktop(JNIEnv * env,jobject desktop)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  */
Java_sun_awt_shell_Win32ShellFolder2_initSpecial(JNIEnv * env,jobject folder,jlong desktopIShellFolder,jint folderType)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  */
Java_sun_awt_shell_Win32ShellFolder2_getNextPIDLEntry(JNIEnv * env,jclass cls,jlong jpIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_copyFirstPIDLEntry(JNIEnv * env,jclass cls,jlong jpIDL)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 
pidlLength(LPITEMIDLIST pIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_combinePIDLs(JNIEnv * env,jclass cls,jlong jppIDL,jlong jpIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_releasePIDL(JNIEnv * env,jclass cls,jlong pIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_releaseIShellFolder(JNIEnv * env,jclass cls,jlong pIShellFolder)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  */
Java_sun_awt_shell_Win32ShellFolder2_compareIDs(JNIEnv * env,jclass cls,jlong jpParentIShellFolder,jlong pIDL1,jlong pIDL2)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  */
Java_sun_awt_shell_Win32ShellFolder2_getAttributes0(JNIEnv * env,jclass cls,jlong jpParentIShellFolder,jlong jpIDL,jint attrsMask)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  */
Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath0(JNIEnv * env,jclass cls,jint csidl)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  */
Java_sun_awt_shell_Win32ShellFolder2_getEnumObjects(JNIEnv * env,jobject folder,jlong pIShellFolder,jboolean isDesktop,jboolean includeHiddenFiles)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  */
Java_sun_awt_shell_Win32ShellFolder2_getNextChild(JNIEnv * env,jobject folder,jlong pEnumObjects)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  */
Java_sun_awt_shell_Win32ShellFolder2_releaseEnumObjects(JNIEnv * env,jobject folder,jlong pEnumObjects)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  */
Java_sun_awt_shell_Win32ShellFolder2_bindToObject(JNIEnv * env,jclass cls,jlong parentIShellFolder,jlong relativePIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_getLinkLocation(JNIEnv * env,jclass cls,jlong parentIShellFolder,jlong relativePIDL,jboolean resolve)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  */
Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0(JNIEnv * env,jclass cls,jlong jpIShellFolder,jstring jname)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  */
Java_sun_awt_shell_Win32ShellFolder2_getDisplayNameOf(JNIEnv * env,jclass cls,jlong parentIShellFolder,jlong relativePIDL,jint attrs)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  */
Java_sun_awt_shell_Win32ShellFolder2_getFolderType(JNIEnv * env,jclass cls,jlong pIDL)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  */
Java_sun_awt_shell_Win32ShellFolder2_getExecutableType(JNIEnv * env,jobject folder,jstring path)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  */
Java_sun_awt_shell_Win32ShellFolder2_getIcon(JNIEnv * env,jclass cls,jstring absolutePath,jboolean getLargeIcon)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 ? SHGFI_LARGEICON : 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  */
Java_sun_awt_shell_Win32ShellFolder2_getIconIndex(JNIEnv * env,jclass cls,jlong pIShellIconL,jlong relativePIDL)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  * Class:     sun.awt.shell.Win32ShellFolder2
917  * Method:    hiResIconAvailable
918  * Signature: (JJ)Z
919  */
Java_sun_awt_shell_Win32ShellFolder2_hiResIconAvailable(JNIEnv * env,jclass cls,jlong pIShellFolderL,jlong relativePIDL)920 JNIEXPORT jboolean JNICALL Java_sun_awt_shell_Win32ShellFolder2_hiResIconAvailable
921     (JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL)
922 {
923     IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
924     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
925     if (pIShellFolder == NULL || pidl == NULL) {
926         return FALSE;
927     }
928     HRESULT hres;
929     IExtractIconW* pIcon;
930     hres = pIShellFolder->GetUIObjectOf(NULL, 1, const_cast<LPCITEMIDLIST*>(&pidl),
931                                         IID_IExtractIconW, NULL, (void**)&pIcon);
932     if (SUCCEEDED(hres)) {
933         WCHAR szBuf[MAX_PATH];
934         INT index;
935         UINT flags;
936         UINT uFlags = GIL_FORSHELL | GIL_ASYNC;
937         hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
938         if (SUCCEEDED(hres)) {
939             pIcon->Release();
940             return wcscmp(szBuf, L"*") != 0;
941         } else if (hres == E_PENDING) {
942             uFlags = GIL_DEFAULTICON;
943             hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
944             if (SUCCEEDED(hres)) {
945                 pIcon->Release();
946                 return wcscmp(szBuf, L"*") != 0;
947             }
948         }
949         pIcon->Release();
950     }
951     return FALSE;
952 }
953 
954 
955 /*
956  * Class:     sun_awt_shell_Win32ShellFolder2
957  * Method:    extractIcon
958  * Signature: (JJIZ)J
959  */
Java_sun_awt_shell_Win32ShellFolder2_extractIcon(JNIEnv * env,jclass cls,jlong pIShellFolderL,jlong relativePIDL,jint size,jboolean getDefaultIcon)960 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
961     (JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL,
962                                 jint size, jboolean getDefaultIcon)
963 {
964     IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
965     LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
966     if (pIShellFolder == NULL || pidl == NULL) {
967         return 0;
968     }
969 
970     HICON hIcon = NULL;
971 
972     HRESULT hres;
973     IExtractIconW* pIcon;
974     hres = pIShellFolder->GetUIObjectOf(NULL, 1, const_cast<LPCITEMIDLIST*>(&pidl),
975                                         IID_IExtractIconW, NULL, (void**)&pIcon);
976     if (SUCCEEDED(hres)) {
977         WCHAR szBuf[MAX_PATH];
978         INT index;
979         UINT flags;
980         UINT uFlags = getDefaultIcon ? GIL_DEFAULTICON : GIL_FORSHELL | GIL_ASYNC;
981         hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
982         if (SUCCEEDED(hres)) {
983             if (size < 24) {
984                 size = 16;
985             }
986             hres = pIcon->Extract(szBuf, index, &hIcon, NULL, size);
987         } else if (hres == E_PENDING) {
988             pIcon->Release();
989             return E_PENDING;
990         }
991         pIcon->Release();
992     }
993     return (jlong)hIcon;
994 }
995 
996 
997 /*
998  * Class:     sun_awt_shell_Win32ShellFolder2
999  * Method:    disposeIcon
1000  * Signature: (J)V
1001  */
Java_sun_awt_shell_Win32ShellFolder2_disposeIcon(JNIEnv * env,jclass cls,jlong hicon)1002 JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_disposeIcon
1003     (JNIEnv* env, jclass cls, jlong hicon)
1004 {
1005     fn_DestroyIcon((HICON)hicon);
1006 }
1007 
1008 /*
1009  * Class:     sun_awt_shell_Win32ShellFolder2
1010  * Method:    getIconBits
1011  * Signature: (J)[I
1012  */
Java_sun_awt_shell_Win32ShellFolder2_getIconBits(JNIEnv * env,jclass cls,jlong hicon)1013 JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits
1014     (JNIEnv* env, jclass cls, jlong hicon)
1015 {
1016     const int MAX_ICON_SIZE = 256;
1017     int iconSize = 0;
1018     jintArray iconBits = NULL;
1019 
1020     BITMAP bmp;
1021     memset(&bmp, 0, sizeof(BITMAP));
1022 
1023     // Get the icon info
1024     ICONINFO iconInfo;
1025     if (fn_GetIconInfo((HICON)hicon, &iconInfo)) {
1026         // Get the screen DC
1027         HDC dc = GetDC(NULL);
1028         if (dc != NULL) {
1029             // find out the icon size in order to deal with different sizes
1030             // delivered depending on HiDPI mode or SD DPI mode.
1031             if (iconInfo.hbmColor) {
1032                 const int nWrittenBytes = GetObject(iconInfo.hbmColor, sizeof(bmp), &bmp);
1033                 if(nWrittenBytes > 0) {
1034                     iconSize = bmp.bmWidth;
1035                 }
1036             } else if (iconInfo.hbmMask) {
1037                 // Icon has no color plane, image data stored in mask
1038                 const int nWrittenBytes = GetObject(iconInfo.hbmMask, sizeof(bmp), &bmp);
1039                 if (nWrittenBytes > 0) {
1040                     iconSize = bmp.bmWidth;
1041                 }
1042             }
1043             // limit iconSize to MAX_ICON_SIZE, so that the colorBits and maskBits
1044             // arrays are big enough.
1045             // (logic: rather show bad icons than overrun the array size)
1046             iconSize = iconSize > MAX_ICON_SIZE ? MAX_ICON_SIZE : iconSize;
1047 
1048             // Set up BITMAPINFO
1049             BITMAPINFO bmi;
1050             memset(&bmi, 0, sizeof(BITMAPINFO));
1051             bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1052             bmi.bmiHeader.biWidth = iconSize;
1053             bmi.bmiHeader.biHeight = -iconSize;
1054             bmi.bmiHeader.biPlanes = 1;
1055             bmi.bmiHeader.biBitCount = 32;
1056             bmi.bmiHeader.biCompression = BI_RGB;
1057             // Extract the color bitmap
1058             int nBits = iconSize * iconSize;
1059             long colorBits[MAX_ICON_SIZE * MAX_ICON_SIZE];
1060             GetDIBits(dc, iconInfo.hbmColor, 0, iconSize, colorBits, &bmi, DIB_RGB_COLORS);
1061             // XP supports alpha in some icons, and depending on device.
1062             // This should take precedence over the icon mask bits.
1063             BOOL hasAlpha = FALSE;
1064             if (IS_WINXP) {
1065                 for (int i = 0; i < nBits; i++) {
1066                     if ((colorBits[i] & 0xff000000) != 0) {
1067                         hasAlpha = TRUE;
1068                         break;
1069                     }
1070                 }
1071             }
1072             if (!hasAlpha) {
1073                 // Extract the mask bitmap
1074                 long maskBits[MAX_ICON_SIZE * MAX_ICON_SIZE];
1075                 GetDIBits(dc, iconInfo.hbmMask, 0, iconSize, maskBits, &bmi, DIB_RGB_COLORS);
1076                 // Copy the mask alphas into the color bits
1077                 for (int i = 0; i < nBits; i++) {
1078                     if (maskBits[i] == 0) {
1079                         colorBits[i] |= 0xff000000;
1080                     }
1081                 }
1082             }
1083             // Release DC
1084             ReleaseDC(NULL, dc);
1085             // Create java array
1086             iconBits = env->NewIntArray(nBits);
1087             if (!(env->ExceptionCheck())) {
1088             // Copy values to java array
1089             env->SetIntArrayRegion(iconBits, 0, nBits, colorBits);
1090         }
1091         }
1092         // Fix 4745575 GDI Resource Leak
1093         // MSDN
1094         // GetIconInfo creates bitmaps for the hbmMask and hbmColor members of ICONINFO.
1095         // The calling application must manage these bitmaps and delete them when they
1096         // are no longer necessary.
1097         ::DeleteObject(iconInfo.hbmColor);
1098         ::DeleteObject(iconInfo.hbmMask);
1099     }
1100     return iconBits;
1101 }
1102 
1103 /*
1104  * Class:     sun_awt_shell_Win32ShellFolder2
1105  * Method:    getStandardViewButton0
1106  * Signature: (IZ)[I
1107  */
Java_sun_awt_shell_Win32ShellFolder2_getStandardViewButton0(JNIEnv * env,jclass cls,jint iconIndex,jboolean smallIcon)1108 JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardViewButton0
1109     (JNIEnv* env, jclass cls, jint iconIndex, jboolean smallIcon)
1110 {
1111     jintArray result = NULL;
1112 
1113     // Create a toolbar
1114     HWND hWndToolbar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
1115         0, 0, 0, 0, 0,
1116         NULL, NULL, NULL, NULL);
1117 
1118     if (hWndToolbar != NULL) {
1119         WPARAM size = smallIcon ? (WPARAM)IDB_VIEW_SMALL_COLOR : (WPARAM)IDB_VIEW_LARGE_COLOR;
1120         SendMessage(hWndToolbar, TB_LOADIMAGES, size, (LPARAM)HINST_COMMCTRL);
1121 
1122         HIMAGELIST hImageList = (HIMAGELIST) SendMessage(hWndToolbar, TB_GETIMAGELIST, 0, 0);
1123 
1124         if (hImageList != NULL) {
1125             HICON hIcon = ImageList_GetIcon(hImageList, iconIndex, ILD_TRANSPARENT);
1126 
1127             if (hIcon != NULL) {
1128                 result = Java_sun_awt_shell_Win32ShellFolder2_getIconBits(env, cls, ptr_to_jlong(hIcon));
1129 
1130                 DestroyIcon(hIcon);
1131             }
1132 
1133             ImageList_Destroy(hImageList);
1134         }
1135 
1136         DestroyWindow(hWndToolbar);
1137     }
1138 
1139     return result;
1140 }
1141 
1142 /*
1143  * Class:     sun_awt_shell_Win32ShellFolder2
1144  * Method:    getSystemIcon
1145  * Signature: (I)J
1146  */
Java_sun_awt_shell_Win32ShellFolder2_getSystemIcon(JNIEnv * env,jclass cls,jint iconID)1147 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getSystemIcon
1148     (JNIEnv* env, jclass cls, jint iconID)
1149 {
1150     return (jlong)LoadIcon(NULL, MAKEINTRESOURCE(iconID));
1151 }
1152 
1153 
1154 /*
1155  * Class:     sun_awt_shell_Win32ShellFolder2
1156  * Method:    getIconResource
1157  * Signature: (Ljava/lang/String;III)J
1158  */
Java_sun_awt_shell_Win32ShellFolder2_getIconResource(JNIEnv * env,jclass cls,jstring libName,jint iconID,jint cxDesired,jint cyDesired)1159 JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource
1160     (JNIEnv* env, jclass cls, jstring libName, jint iconID,
1161      jint cxDesired, jint cyDesired)
1162 {
1163     const char *pLibName = env->GetStringUTFChars(libName, NULL);
1164     JNU_CHECK_EXCEPTION_RETURN(env, 0);
1165     HINSTANCE libHandle = (HINSTANCE)JDK_LoadSystemLibrary(pLibName);
1166     if (pLibName != NULL) {
1167         env->ReleaseStringUTFChars(libName, pLibName);
1168     }
1169     if (libHandle != NULL) {
1170         return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID),
1171                                       IMAGE_ICON, cxDesired, cyDesired,
1172                                       0));
1173     }
1174     return 0;
1175 }
1176 
1177 
1178 /*
1179  * Helper function for creating Java column info object
1180  */
CreateColumnInfo(JNIEnv * pEnv,jclass * pClass,jmethodID * pConstructor,int colNum,SHELLDETAILS * psd,ULONG visible)1181 static jobject CreateColumnInfo(JNIEnv *pEnv,
1182                                 jclass *pClass, jmethodID *pConstructor,
1183                                 int colNum, SHELLDETAILS *psd, ULONG visible)
1184 {
1185     jstring str = jstringFromSTRRET(pEnv, NULL, &(psd->str));
1186     JNU_CHECK_EXCEPTION_RETURN(pEnv, NULL);
1187 
1188     // Convert ShellFolder column names to locale-sensitive names
1189     if (colNum == 0) {
1190         str = lsName;
1191     } else if (colNum == 1) {
1192         str = lsSize;
1193     } else if (colNum == 2) {
1194         str = lsType;
1195     } else if (colNum == 3) {
1196         str = lsDate;
1197     }
1198     return pEnv->NewObject(*pClass, *pConstructor,
1199                     str,
1200                     (jint)(psd->cxChar * 6), // TODO: is 6 OK for converting chars to pixels?
1201                     (jint)psd->fmt, (jboolean) visible);
1202 }
1203 
1204 
1205 /*
1206  * Class:     sun_awt_shell_Win32ShellFolder2
1207  * Method:    doGetColumnInfo
1208  * Signature: (J)[Lsun/awt/shell/ShellFolderColumnInfo;
1209  */
1210 JNIEXPORT jobjectArray JNICALL
Java_sun_awt_shell_Win32ShellFolder2_doGetColumnInfo(JNIEnv * env,jobject obj,jlong iShellFolder)1211     Java_sun_awt_shell_Win32ShellFolder2_doGetColumnInfo
1212             (JNIEnv *env, jobject obj, jlong iShellFolder)
1213 {
1214 
1215     HRESULT hr;
1216     IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1217     IUnknown *pIUnknown = NULL;
1218 
1219     jclass columnClass = env->FindClass("sun/awt/shell/ShellFolderColumnInfo");
1220     if(NULL == columnClass) {
1221         return NULL;
1222     }
1223 
1224     jmethodID columnConstructor =
1225         env->GetMethodID(columnClass, "<init>", "(Ljava/lang/String;IIZ)V");
1226     if(NULL == columnConstructor) {
1227         return NULL;
1228     }
1229 
1230     // We'are asking the object the list of available columns
1231     SHELLDETAILS sd;
1232 
1233     hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1234     if(SUCCEEDED (hr)) {
1235 
1236         // The folder exposes IShellFolder2 interface
1237         IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1238 
1239         // Count columns
1240         int colNum = -1;
1241         hr = S_OK;
1242         do{
1243             hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd);
1244         } while (SUCCEEDED (hr));
1245 
1246         jobjectArray columns =
1247             env->NewObjectArray((jsize) colNum, columnClass, NULL);
1248         if(NULL == columns) {
1249             pIShellFolder2->Release();
1250             return NULL;
1251         }
1252 
1253         // Fill column details list
1254         SHCOLSTATEF csFlags;
1255         colNum = 0;
1256         hr = S_OK;
1257         while (SUCCEEDED (hr)) {
1258             hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd);
1259 
1260             if (SUCCEEDED (hr)) {
1261                 hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags);
1262                 if (SUCCEEDED (hr)) {
1263                     if(!(csFlags & SHCOLSTATE_HIDDEN)) {
1264                         jobject column = CreateColumnInfo(env,
1265                                             &columnClass, &columnConstructor,
1266                                             colNum, &sd, csFlags & SHCOLSTATE_ONBYDEFAULT);
1267                         if(!column){
1268                             pIShellFolder2->Release();
1269                             return NULL;
1270                         }
1271                         env->SetObjectArrayElement(columns, (jsize) colNum, column);
1272                     }
1273                 }
1274                 colNum++;
1275             }
1276         }
1277 
1278         pIShellFolder2->Release();
1279 
1280         return columns;
1281     }
1282 
1283     hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1284     if(SUCCEEDED (hr)) {
1285         // The folder exposes IShellDetails interface
1286         IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1287 
1288         // Count columns
1289         int colNum = -1;
1290         hr = S_OK;
1291         do{
1292             hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd);
1293         } while (SUCCEEDED (hr));
1294 
1295         jobjectArray columns =
1296             env->NewObjectArray((jsize) colNum, columnClass, NULL);
1297         if(NULL == columns) {
1298             pIShellDetails->Release();
1299             return NULL;
1300         }
1301 
1302         // Fill column details list
1303         colNum = 0;
1304         hr = S_OK;
1305         while (SUCCEEDED (hr)) {
1306             hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd);
1307             if (SUCCEEDED (hr)) {
1308                 jobject column = CreateColumnInfo(env,
1309                                     &columnClass, &columnConstructor,
1310                                     colNum, &sd, 1);
1311                 if(!column){
1312                     pIShellDetails->Release();
1313                     return NULL;
1314                 }
1315                 env->SetObjectArrayElement(columns, (jsize) colNum++, column);
1316             }
1317         }
1318 
1319         pIShellDetails->Release();
1320 
1321         return columns;
1322     }
1323 
1324     // The folder exposes neither IShellFolder2 nor IShelDetails
1325     return NULL;
1326 
1327 }
1328 
1329 /*
1330  * Class:     sun_awt_shell_Win32ShellFolder2
1331  * Method:    doGetColumnValue
1332  * Signature: (JJI)Ljava/lang/Object;
1333  */
1334 JNIEXPORT jobject JNICALL
Java_sun_awt_shell_Win32ShellFolder2_doGetColumnValue(JNIEnv * env,jobject obj,jlong iShellFolder,jlong jpidl,jint columnIdx)1335     Java_sun_awt_shell_Win32ShellFolder2_doGetColumnValue
1336             (JNIEnv *env, jobject obj, jlong iShellFolder,
1337             jlong jpidl, jint columnIdx)
1338 {
1339 
1340     HRESULT hr;
1341     IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1342     IUnknown *pIUnknown = NULL;
1343 
1344 
1345     LPITEMIDLIST pidl = (LPITEMIDLIST) jpidl;
1346     SHELLDETAILS sd;
1347 
1348     hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1349     if(SUCCEEDED (hr)) {
1350         // The folder exposes IShellFolder2 interface
1351         IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1352         hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1353         pIShellFolder2->Release();
1354         if (SUCCEEDED (hr)) {
1355             STRRET strRet = sd.str;
1356             return jstringFromSTRRET(env, pidl, &strRet);
1357         }
1358     }
1359 
1360     hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1361     if(SUCCEEDED (hr)) {
1362         // The folder exposes IShellDetails interface
1363         IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1364         hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1365         pIShellDetails->Release();
1366         if (SUCCEEDED (hr)) {
1367             STRRET strRet = sd.str;
1368             return jstringFromSTRRET(env, pidl, &strRet);
1369         }
1370     }
1371 
1372     // The folder exposes neither IShellFolder2 nor IShelDetails
1373     return NULL;
1374 }
1375 
1376 /*
1377  * Class:     sun_awt_shell_Win32ShellFolder2
1378  * Method:    compareIDsByColumn
1379  * Signature: (JJJI)I
1380  */
1381 JNIEXPORT jint JNICALL
Java_sun_awt_shell_Win32ShellFolder2_compareIDsByColumn(JNIEnv * env,jclass cls,jlong jpParentIShellFolder,jlong pIDL1,jlong pIDL2,jint columnIdx)1382     Java_sun_awt_shell_Win32ShellFolder2_compareIDsByColumn
1383             (JNIEnv* env, jclass cls, jlong jpParentIShellFolder,
1384             jlong pIDL1, jlong pIDL2, jint columnIdx)
1385 {
1386     IShellFolder* pParentIShellFolder = (IShellFolder*)jpParentIShellFolder;
1387     if (pParentIShellFolder == NULL) {
1388         return 0;
1389     }
1390 
1391     HRESULT hr = pParentIShellFolder->CompareIDs(
1392                                             (UINT) columnIdx,
1393                                             (LPCITEMIDLIST) pIDL1,
1394                                             (LPCITEMIDLIST) pIDL2);
1395     if (SUCCEEDED (hr)) {
1396         return (jint) (short) HRESULT_CODE(hr);
1397     }
1398 
1399     return 0;
1400 }
1401 
1402 /*
1403  * Class:     sun_awt_shell_Win32ShellFolder2
1404  * Method:    loadKnownFolders
1405  * Signature: (V)[BLsun/awt/shell/Win32ShellFolder2$KnownfolderDefenition;
1406  */
Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders(JNIEnv * env,jclass cls)1407 JNIEXPORT jobjectArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders
1408     (JNIEnv* env, jclass cls )
1409 {
1410     IKnownFolderManager* pkfm = NULL;
1411     HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL,
1412                                 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm));
1413     if (!SUCCEEDED(hr)) return NULL;
1414 
1415     TRY;
1416 
1417     jclass cl = env->FindClass("sun/awt/shell/Win32ShellFolder2$KnownFolderDefinition");
1418     CHECK_NULL_RETURN(cl, NULL);
1419     DEFINE_FIELD_ID(field_guid, cl, "guid", "Ljava/lang/String;")
1420     DEFINE_FIELD_ID(field_name, cl, "name", "Ljava/lang/String;");
1421     DEFINE_FIELD_ID(field_description, cl, "description", "Ljava/lang/String;");
1422     DEFINE_FIELD_ID(field_parent, cl, "parent", "Ljava/lang/String;");
1423     DEFINE_FIELD_ID(field_relativePath, cl, "relativePath", "Ljava/lang/String;");
1424     DEFINE_FIELD_ID(field_parsingName, cl, "parsingName", "Ljava/lang/String;");
1425     DEFINE_FIELD_ID(field_tooltip, cl, "tooltip", "Ljava/lang/String;");
1426     DEFINE_FIELD_ID(field_localizedName, cl, "localizedName", "Ljava/lang/String;");
1427     DEFINE_FIELD_ID(field_icon, cl, "icon", "Ljava/lang/String;");
1428     DEFINE_FIELD_ID(field_security, cl, "security", "Ljava/lang/String;");
1429     DEFINE_FIELD_ID(field_path, cl, "path", "Ljava/lang/String;");
1430     DEFINE_FIELD_ID(field_saveLocation, cl, "saveLocation", "Ljava/lang/String;");
1431     DEFINE_FIELD_ID(field_category, cl, "category", "I");
1432     DEFINE_FIELD_ID(field_attributes, cl, "attributes", "J");
1433     DEFINE_FIELD_ID(field_defenitionFlags, cl, "defenitionFlags", "I");
1434     DEFINE_FIELD_ID(field_ftidType, cl, "ftidType", "Ljava/lang/String;");
1435 
1436     jobjectArray result = NULL;
1437     KNOWNFOLDERID* pFoldersIds = NULL;
1438     UINT count = 0;
1439     if (SUCCEEDED(pkfm->GetFolderIds(&pFoldersIds, &count))) {
1440         jmethodID initMethod;
1441         try {
1442             result = env->NewObjectArray(count, cl, NULL);
1443             initMethod = env->GetMethodID(cl, "<init>", "()V");
1444             EXCEPTION_CHECK
1445         } catch (std::bad_alloc&) {
1446             CoTaskMemFree(pFoldersIds);
1447             pkfm->Release();
1448             throw;
1449         }
1450         for(UINT i = 0; i < count; ++i)
1451         {
1452             jobject fld;
1453             const KNOWNFOLDERID& folderId = pFoldersIds[i];
1454             LPOLESTR guid = NULL;
1455             try {
1456                 fld = env->NewObject(cl, initMethod);
1457                 if (fld) {
1458                     env->SetObjectArrayElement(result, i, fld);
1459                 }
1460                 EXCEPTION_CHECK
1461 
1462                 if (SUCCEEDED(StringFromCLSID(folderId, &guid))) {
1463                     jstring jstr = JNU_NewStringPlatform(env, guid);
1464                     if (jstr) {
1465                         env->SetObjectField(fld, field_guid, jstr);
1466                     }
1467                     CoTaskMemFree(guid);
1468                     EXCEPTION_CHECK
1469                 }
1470             } catch (std::bad_alloc&) {
1471                 CoTaskMemFree(pFoldersIds);
1472                 pkfm->Release();
1473                 throw;
1474             }
1475 
1476             IKnownFolder* pFolder = NULL;
1477             if (SUCCEEDED(pkfm->GetFolder(folderId, &pFolder))) {
1478                 KNOWNFOLDER_DEFINITION kfDef;
1479                 if (SUCCEEDED(pFolder->GetFolderDefinition(&kfDef)))
1480                 {
1481                     try {
1482                         jstring jstr = JNU_NewStringPlatform(env, kfDef.pszName);
1483                         if(jstr) {
1484                             env->SetObjectField(fld, field_name, jstr);
1485                         }
1486                         EXCEPTION_CHECK
1487                         if (kfDef.pszDescription) {
1488                             jstr = JNU_NewStringPlatform(env, kfDef.pszDescription);
1489                             if (jstr) {
1490                                 env->SetObjectField(fld, field_description, jstr);
1491                             }
1492                             EXCEPTION_CHECK
1493                         }
1494                         EXCEPTION_CHECK
1495                         if (SUCCEEDED(StringFromCLSID(kfDef.fidParent, &guid))) {
1496                             jstr = JNU_NewStringPlatform(env, guid);
1497                             if (jstr) {
1498                                 env->SetObjectField(fld, field_parent, jstr);
1499                             }
1500                             CoTaskMemFree(guid);
1501                             EXCEPTION_CHECK
1502                         }
1503                         if (kfDef.pszRelativePath) {
1504                             jstr = JNU_NewStringPlatform(env, kfDef.pszRelativePath);
1505                             if (jstr) {
1506                                 env->SetObjectField(fld, field_relativePath, jstr);
1507                             }
1508                             EXCEPTION_CHECK
1509                         }
1510                         if (kfDef.pszParsingName) {
1511                             jstr = JNU_NewStringPlatform(env, kfDef.pszParsingName);
1512                             if (jstr) {
1513                                 env->SetObjectField(fld, field_parsingName, jstr);
1514                             }
1515                             EXCEPTION_CHECK
1516                         }
1517                         if (kfDef.pszTooltip) {
1518                             jstr = JNU_NewStringPlatform(env, kfDef.pszTooltip);
1519                             if (jstr) {
1520                                 env->SetObjectField(fld, field_tooltip, jstr);
1521                             }
1522                             EXCEPTION_CHECK
1523                         }
1524                         if (kfDef.pszLocalizedName) {
1525                             jstr = JNU_NewStringPlatform(env, kfDef.pszLocalizedName);
1526                             if (jstr) {
1527                                 env->SetObjectField(fld, field_localizedName, jstr);
1528                             }
1529                             EXCEPTION_CHECK
1530                         }
1531                         if (kfDef.pszIcon) {
1532                             jstr = JNU_NewStringPlatform(env, kfDef.pszIcon);
1533                             if (jstr) {
1534                                 env->SetObjectField(fld, field_icon, jstr);
1535                             }
1536                             EXCEPTION_CHECK
1537                         }
1538                         if (kfDef.pszSecurity) {
1539                             jstr = JNU_NewStringPlatform(env, kfDef.pszSecurity);
1540                             if (jstr) {
1541                                 env->SetObjectField(fld, field_security, jstr);
1542                             }
1543                             EXCEPTION_CHECK
1544                         }
1545                         if (SUCCEEDED(StringFromCLSID(kfDef.ftidType, &guid))) {
1546                             jstr = JNU_NewStringPlatform(env, guid);
1547                             if (jstr) {
1548                                 env->SetObjectField(fld, field_ftidType, jstr);
1549                             }
1550                             CoTaskMemFree(guid);
1551                             EXCEPTION_CHECK
1552                         }
1553                         env->SetIntField(fld, field_category, kfDef.category);
1554                         env->SetIntField(fld, field_defenitionFlags, kfDef.kfdFlags);
1555                         env->SetLongField(fld, field_attributes, kfDef.dwAttributes);
1556 
1557                         LPWSTR folderPath = NULL;
1558                         if (SUCCEEDED(pFolder->GetPath(KF_FLAG_NO_ALIAS, &folderPath))
1559                                     && folderPath) {
1560                             jstr = JNU_NewStringPlatform(env, folderPath);
1561                             if (jstr) {
1562                                 env->SetObjectField(fld, field_path, jstr);
1563                             }
1564                             CoTaskMemFree(folderPath);
1565                             EXCEPTION_CHECK
1566                         }
1567 
1568                         IShellLibrary *plib = NULL;
1569                         hr = CoCreateInstance(CLSID_ShellLibrary, NULL,
1570                                          CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&plib));
1571                         if (SUCCEEDED(hr)) {
1572                             hr = plib->LoadLibraryFromKnownFolder(folderId, STGM_READWRITE);
1573                             if (SUCCEEDED(hr)) {
1574                                 IShellItem *item = NULL;
1575                                 hr = plib->GetDefaultSaveFolder(DSFT_DETECT,
1576                                         IID_PPV_ARGS(&item));
1577                                 if (SUCCEEDED(hr) && item) {
1578                                     LPWSTR loc = NULL;
1579                                     hr = item->GetDisplayName(SIGDN_FILESYSPATH, &loc);
1580                                     if (SUCCEEDED(hr) && loc)
1581                                     {
1582                                         jstr = JNU_NewStringPlatform(env, loc);
1583                                         if (jstr) {
1584                                             env->SetObjectField(fld, field_saveLocation, jstr);
1585                                         }
1586                                         CoTaskMemFree(loc);
1587                                     }
1588                                     item->Release();
1589                                 }
1590                             }
1591                             plib->Release();
1592                             EXCEPTION_CHECK
1593                         }
1594                         FreeKnownFolderDefinitionFields(&kfDef);
1595                     } catch (std::bad_alloc&) {
1596                         FreeKnownFolderDefinitionFields(&kfDef);
1597                         pFolder->Release();
1598                         CoTaskMemFree(pFoldersIds);
1599                         pkfm->Release();
1600                         throw;
1601                     }
1602                 }
1603             }
1604             pFolder->Release();
1605         }
1606         CoTaskMemFree(pFoldersIds);
1607     }
1608     pkfm->Release();
1609     return result;
1610     CATCH_BAD_ALLOC_RET(NULL);
1611 }
1612 
1613 } // extern "C"
1614