1/*
2 * Copyright (c) 2003, 2017, 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}
57DEFINE_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
62DEFINE_SHLGUID(IID_IShellLinkW,         0x000214F9L, 0, 0);
63DEFINE_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
81typedef BOOL (WINAPI *DestroyIconType)(HICON);
82typedef HINSTANCE (WINAPI *FindExecutableType)(LPCTSTR,LPCTSTR,LPTSTR);
83typedef HICON (WINAPI *ImageList_GetIconType)(HIMAGELIST,int,UINT);
84typedef BOOL (WINAPI *GetIconInfoType)(HICON,PICONINFO);
85typedef HRESULT (WINAPI *SHGetDesktopFolderType)(IShellFolder**);
86typedef DWORD* (WINAPI *SHGetFileInfoType)(LPCTSTR,DWORD,SHFILEINFO*,UINT,UINT);
87typedef HRESULT (WINAPI *SHGetMallocType)(IMalloc**);
88typedef BOOL (WINAPI *SHGetPathFromIDListType)(LPCITEMIDLIST,LPTSTR);
89typedef HRESULT (WINAPI *SHGetSpecialFolderLocationType)(HWND,int,LPITEMIDLIST*);
90
91static DestroyIconType fn_DestroyIcon;
92static FindExecutableType fn_FindExecutable;
93static GetIconInfoType fn_GetIconInfo;
94static ImageList_GetIconType fn_ImageList_GetIcon;
95static SHGetDesktopFolderType fn_SHGetDesktopFolder;
96static SHGetFileInfoType fn_SHGetFileInfo;
97static SHGetMallocType fn_SHGetMalloc;
98static SHGetPathFromIDListType fn_SHGetPathFromIDList;
99static SHGetSpecialFolderLocationType fn_SHGetSpecialFolderLocation;
100
101// Field IDs
102static jmethodID MID_pIShellFolder;
103static jfieldID FID_pIShellIcon;
104static jmethodID MID_relativePIDL;
105static jfieldID FID_displayName;
106static jfieldID FID_folderType;
107
108// Other statics
109static IMalloc* pMalloc;
110static IShellFolder* pDesktop;
111
112// locale sensitive folder info
113static jfieldID FID_lsName;
114static jfieldID FID_lsSize;
115static jfieldID FID_lsType;
116static jfieldID FID_lsDate;
117static jstring lsName;
118static jstring lsSize;
119static jstring lsType;
120static 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
134extern "C" {
135
136static 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
215static 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 */
242JNIEXPORT 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*/
297JNIEXPORT 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*/
313JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolderManager2_uninitializeCom
314        (JNIEnv* env, jclass cls)
315{
316    ::CoUninitialize();
317}
318
319static 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 */
338JNIEXPORT 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 */
350JNIEXPORT 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 */
378JNIEXPORT 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 */
416JNIEXPORT 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 */
445JNIEXPORT 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
475static 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 */
490JNIEXPORT 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 */
520JNIEXPORT 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 */
534JNIEXPORT 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 */
548JNIEXPORT 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 */
564JNIEXPORT 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 */
586JNIEXPORT 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 */
608JNIEXPORT 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 */
637JNIEXPORT 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 */
656JNIEXPORT 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 */
671JNIEXPORT 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 */
696JNIEXPORT 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, 0);
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 */
775JNIEXPORT 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 */
810JNIEXPORT 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 */
837JNIEXPORT 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 */
853JNIEXPORT 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 */
875JNIEXPORT 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 */
895JNIEXPORT 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 */
921JNIEXPORT 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 */
969JNIEXPORT 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 */
980JNIEXPORT 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 */
1075JNIEXPORT 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 */
1114JNIEXPORT 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 */
1126JNIEXPORT 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 (libHandle != NULL) {
1134        UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0;
1135        return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID),
1136                                      IMAGE_ICON, cxDesired, cyDesired,
1137                                      fuLoad));
1138    }
1139    return 0;
1140}
1141
1142
1143/*
1144 * Helper function for creating Java column info object
1145 */
1146static jobject CreateColumnInfo(JNIEnv *pEnv,
1147                                jclass *pClass, jmethodID *pConstructor,
1148                                int colNum, SHELLDETAILS *psd, ULONG visible)
1149{
1150    jstring str = jstringFromSTRRET(pEnv, NULL, &(psd->str));
1151    JNU_CHECK_EXCEPTION_RETURN(pEnv, NULL);
1152
1153    // Convert ShellFolder column names to locale-sensitive names
1154    if (colNum == 0) {
1155        str = lsName;
1156    } else if (colNum == 1) {
1157        str = lsSize;
1158    } else if (colNum == 2) {
1159        str = lsType;
1160    } else if (colNum == 3) {
1161        str = lsDate;
1162    }
1163    return pEnv->NewObject(*pClass, *pConstructor,
1164                    str,
1165                    (jint)(psd->cxChar * 6), // TODO: is 6 OK for converting chars to pixels?
1166                    (jint)psd->fmt, (jboolean) visible);
1167}
1168
1169
1170/*
1171 * Class:     sun_awt_shell_Win32ShellFolder2
1172 * Method:    doGetColumnInfo
1173 * Signature: (J)[Lsun/awt/shell/ShellFolderColumnInfo;
1174 */
1175JNIEXPORT jobjectArray JNICALL
1176    Java_sun_awt_shell_Win32ShellFolder2_doGetColumnInfo
1177            (JNIEnv *env, jobject obj, jlong iShellFolder)
1178{
1179
1180    HRESULT hr;
1181    IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1182    IUnknown *pIUnknown = NULL;
1183
1184    jclass columnClass = env->FindClass("sun/awt/shell/ShellFolderColumnInfo");
1185    if(NULL == columnClass) {
1186        return NULL;
1187    }
1188
1189    jmethodID columnConstructor =
1190        env->GetMethodID(columnClass, "<init>", "(Ljava/lang/String;IIZ)V");
1191    if(NULL == columnConstructor) {
1192        return NULL;
1193    }
1194
1195    // We'are asking the object the list of available columns
1196    SHELLDETAILS sd;
1197
1198    hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1199    if(SUCCEEDED (hr)) {
1200
1201        // The folder exposes IShellFolder2 interface
1202        IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1203
1204        // Count columns
1205        int colNum = -1;
1206        hr = S_OK;
1207        do{
1208            hr = pIShellFolder2->GetDetailsOf(NULL, ++colNum, &sd);
1209        } while (SUCCEEDED (hr));
1210
1211        jobjectArray columns =
1212            env->NewObjectArray((jsize) colNum, columnClass, NULL);
1213        if(NULL == columns) {
1214            pIShellFolder2->Release();
1215            return NULL;
1216        }
1217
1218        // Fill column details list
1219        SHCOLSTATEF csFlags;
1220        colNum = 0;
1221        hr = S_OK;
1222        while (SUCCEEDED (hr)) {
1223            hr = pIShellFolder2->GetDetailsOf(NULL, colNum, &sd);
1224
1225            if (SUCCEEDED (hr)) {
1226                hr = pIShellFolder2->GetDefaultColumnState(colNum, &csFlags);
1227                if (SUCCEEDED (hr)) {
1228                    if(!(csFlags & SHCOLSTATE_HIDDEN)) {
1229                        jobject column = CreateColumnInfo(env,
1230                                            &columnClass, &columnConstructor,
1231                                            colNum, &sd, csFlags & SHCOLSTATE_ONBYDEFAULT);
1232                        if(!column){
1233                            pIShellFolder2->Release();
1234                            return NULL;
1235                        }
1236                        env->SetObjectArrayElement(columns, (jsize) colNum, column);
1237                    }
1238                }
1239                colNum++;
1240            }
1241        }
1242
1243        pIShellFolder2->Release();
1244
1245        return columns;
1246    }
1247
1248    hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1249    if(SUCCEEDED (hr)) {
1250        // The folder exposes IShellDetails interface
1251        IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1252
1253        // Count columns
1254        int colNum = -1;
1255        hr = S_OK;
1256        do{
1257            hr = pIShellDetails->GetDetailsOf(NULL, ++colNum, &sd);
1258        } while (SUCCEEDED (hr));
1259
1260        jobjectArray columns =
1261            env->NewObjectArray((jsize) colNum, columnClass, NULL);
1262        if(NULL == columns) {
1263            pIShellDetails->Release();
1264            return NULL;
1265        }
1266
1267        // Fill column details list
1268        colNum = 0;
1269        hr = S_OK;
1270        while (SUCCEEDED (hr)) {
1271            hr = pIShellDetails->GetDetailsOf(NULL, colNum, &sd);
1272            if (SUCCEEDED (hr)) {
1273                jobject column = CreateColumnInfo(env,
1274                                    &columnClass, &columnConstructor,
1275                                    colNum, &sd, 1);
1276                if(!column){
1277                    pIShellDetails->Release();
1278                    return NULL;
1279                }
1280                env->SetObjectArrayElement(columns, (jsize) colNum++, column);
1281            }
1282        }
1283
1284        pIShellDetails->Release();
1285
1286        return columns;
1287    }
1288
1289    // The folder exposes neither IShellFolder2 nor IShelDetails
1290    return NULL;
1291
1292}
1293
1294/*
1295 * Class:     sun_awt_shell_Win32ShellFolder2
1296 * Method:    doGetColumnValue
1297 * Signature: (JJI)Ljava/lang/Object;
1298 */
1299JNIEXPORT jobject JNICALL
1300    Java_sun_awt_shell_Win32ShellFolder2_doGetColumnValue
1301            (JNIEnv *env, jobject obj, jlong iShellFolder,
1302            jlong jpidl, jint columnIdx)
1303{
1304
1305    HRESULT hr;
1306    IShellFolder *pIShellFolder = (IShellFolder*) iShellFolder;
1307    IUnknown *pIUnknown = NULL;
1308
1309
1310    LPITEMIDLIST pidl = (LPITEMIDLIST) jpidl;
1311    SHELLDETAILS sd;
1312
1313    hr = pIShellFolder->QueryInterface(IID_IShellFolder2, (void**)&pIUnknown);
1314    if(SUCCEEDED (hr)) {
1315        // The folder exposes IShellFolder2 interface
1316        IShellFolder2 *pIShellFolder2 = (IShellFolder2*) pIUnknown;
1317        hr = pIShellFolder2->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1318        pIShellFolder2->Release();
1319        if (SUCCEEDED (hr)) {
1320            STRRET strRet = sd.str;
1321            return jstringFromSTRRET(env, pidl, &strRet);
1322        }
1323    }
1324
1325    hr = pIShellFolder->CreateViewObject(NULL, IID_IShellDetails, (void**)&pIUnknown);
1326    if(SUCCEEDED (hr)) {
1327        // The folder exposes IShellDetails interface
1328        IShellDetails *pIShellDetails = (IShellDetails*) pIUnknown;
1329        hr = pIShellDetails->GetDetailsOf(pidl, (UINT)columnIdx, &sd);
1330        pIShellDetails->Release();
1331        if (SUCCEEDED (hr)) {
1332            STRRET strRet = sd.str;
1333            return jstringFromSTRRET(env, pidl, &strRet);
1334        }
1335    }
1336
1337    // The folder exposes neither IShellFolder2 nor IShelDetails
1338    return NULL;
1339}
1340
1341/*
1342 * Class:     sun_awt_shell_Win32ShellFolder2
1343 * Method:    compareIDsByColumn
1344 * Signature: (JJJI)I
1345 */
1346JNIEXPORT jint JNICALL
1347    Java_sun_awt_shell_Win32ShellFolder2_compareIDsByColumn
1348            (JNIEnv* env, jclass cls, jlong jpParentIShellFolder,
1349            jlong pIDL1, jlong pIDL2, jint columnIdx)
1350{
1351    IShellFolder* pParentIShellFolder = (IShellFolder*)jpParentIShellFolder;
1352    if (pParentIShellFolder == NULL) {
1353        return 0;
1354    }
1355
1356    HRESULT hr = pParentIShellFolder->CompareIDs(
1357                                            (UINT) columnIdx,
1358                                            (LPCITEMIDLIST) pIDL1,
1359                                            (LPCITEMIDLIST) pIDL2);
1360    if (SUCCEEDED (hr)) {
1361        return (jint) (short) HRESULT_CODE(hr);
1362    }
1363
1364    return 0;
1365}
1366
1367/*
1368 * Class:     sun_awt_shell_Win32ShellFolder2
1369 * Method:    loadKnownFolders
1370 * Signature: (V)[BLsun/awt/shell/Win32ShellFolder2$KnownfolderDefenition;
1371 */
1372JNIEXPORT jobjectArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders
1373    (JNIEnv* env, jclass cls )
1374{
1375    IKnownFolderManager* pkfm = NULL;
1376    HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL,
1377                                CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm));
1378    if (!SUCCEEDED(hr)) return NULL;
1379
1380    TRY;
1381
1382    jclass cl = env->FindClass("sun/awt/shell/Win32ShellFolder2$KnownFolderDefinition");
1383    CHECK_NULL_RETURN(cl, NULL);
1384    DEFINE_FIELD_ID(field_guid, cl, "guid", "Ljava/lang/String;")
1385    DEFINE_FIELD_ID(field_name, cl, "name", "Ljava/lang/String;");
1386    DEFINE_FIELD_ID(field_description, cl, "description", "Ljava/lang/String;");
1387    DEFINE_FIELD_ID(field_parent, cl, "parent", "Ljava/lang/String;");
1388    DEFINE_FIELD_ID(field_relativePath, cl, "relativePath", "Ljava/lang/String;");
1389    DEFINE_FIELD_ID(field_parsingName, cl, "parsingName", "Ljava/lang/String;");
1390    DEFINE_FIELD_ID(field_tooltip, cl, "tooltip", "Ljava/lang/String;");
1391    DEFINE_FIELD_ID(field_localizedName, cl, "localizedName", "Ljava/lang/String;");
1392    DEFINE_FIELD_ID(field_icon, cl, "icon", "Ljava/lang/String;");
1393    DEFINE_FIELD_ID(field_security, cl, "security", "Ljava/lang/String;");
1394    DEFINE_FIELD_ID(field_path, cl, "path", "Ljava/lang/String;");
1395    DEFINE_FIELD_ID(field_saveLocation, cl, "saveLocation", "Ljava/lang/String;");
1396    DEFINE_FIELD_ID(field_category, cl, "category", "I");
1397    DEFINE_FIELD_ID(field_attributes, cl, "attributes", "J");
1398    DEFINE_FIELD_ID(field_defenitionFlags, cl, "defenitionFlags", "I");
1399    DEFINE_FIELD_ID(field_ftidType, cl, "ftidType", "Ljava/lang/String;");
1400
1401    jobjectArray result;
1402    KNOWNFOLDERID* pFoldersIds = NULL;
1403    UINT count = 0;
1404    if (SUCCEEDED(pkfm->GetFolderIds(&pFoldersIds, &count))) {
1405        jmethodID initMethod;
1406        try {
1407            result = env->NewObjectArray(count, cl, NULL);
1408            initMethod = env->GetMethodID(cl, "<init>", "()V");
1409            EXCEPTION_CHECK
1410        } catch (std::bad_alloc&) {
1411            CoTaskMemFree(pFoldersIds);
1412            pkfm->Release();
1413            throw;
1414        }
1415        for(UINT i = 0; i < count; ++i)
1416        {
1417            jobject fld;
1418            const KNOWNFOLDERID& folderId = pFoldersIds[i];
1419            LPOLESTR guid = NULL;
1420            try {
1421                fld = env->NewObject(cl, initMethod);
1422                if (fld) {
1423                    env->SetObjectArrayElement(result, i, fld);
1424                }
1425                EXCEPTION_CHECK
1426
1427                if (SUCCEEDED(StringFromCLSID(folderId, &guid))) {
1428                    jstring jstr = JNU_NewStringPlatform(env, guid);
1429                    if (jstr) {
1430                        env->SetObjectField(fld, field_guid, jstr);
1431                    }
1432                    CoTaskMemFree(guid);
1433                    EXCEPTION_CHECK
1434                }
1435            } catch (std::bad_alloc&) {
1436                CoTaskMemFree(pFoldersIds);
1437                pkfm->Release();
1438                throw;
1439            }
1440
1441            IKnownFolder* pFolder = NULL;
1442            if (SUCCEEDED(pkfm->GetFolder(folderId, &pFolder))) {
1443                KNOWNFOLDER_DEFINITION kfDef;
1444                if (SUCCEEDED(pFolder->GetFolderDefinition(&kfDef)))
1445                {
1446                    try {
1447                        jstring jstr = JNU_NewStringPlatform(env, kfDef.pszName);
1448                        if(jstr) {
1449                            env->SetObjectField(fld, field_name, jstr);
1450                        }
1451                        EXCEPTION_CHECK
1452                        if (kfDef.pszDescription) {
1453                            jstr = JNU_NewStringPlatform(env, kfDef.pszDescription);
1454                            if (jstr) {
1455                                env->SetObjectField(fld, field_description, jstr);
1456                            }
1457                            EXCEPTION_CHECK
1458                        }
1459                        EXCEPTION_CHECK
1460                        if (SUCCEEDED(StringFromCLSID(kfDef.fidParent, &guid))) {
1461                            jstr = JNU_NewStringPlatform(env, guid);
1462                            if (jstr) {
1463                                env->SetObjectField(fld, field_parent, jstr);
1464                            }
1465                            CoTaskMemFree(guid);
1466                            EXCEPTION_CHECK
1467                        }
1468                        if (kfDef.pszRelativePath) {
1469                            jstr = JNU_NewStringPlatform(env, kfDef.pszRelativePath);
1470                            if (jstr) {
1471                                env->SetObjectField(fld, field_relativePath, jstr);
1472                            }
1473                            EXCEPTION_CHECK
1474                        }
1475                        if (kfDef.pszParsingName) {
1476                            jstr = JNU_NewStringPlatform(env, kfDef.pszParsingName);
1477                            if (jstr) {
1478                                env->SetObjectField(fld, field_parsingName, jstr);
1479                            }
1480                            EXCEPTION_CHECK
1481                        }
1482                        if (kfDef.pszTooltip) {
1483                            jstr = JNU_NewStringPlatform(env, kfDef.pszTooltip);
1484                            if (jstr) {
1485                                env->SetObjectField(fld, field_tooltip, jstr);
1486                            }
1487                            EXCEPTION_CHECK
1488                        }
1489                        if (kfDef.pszLocalizedName) {
1490                            jstr = JNU_NewStringPlatform(env, kfDef.pszLocalizedName);
1491                            if (jstr) {
1492                                env->SetObjectField(fld, field_localizedName, jstr);
1493                            }
1494                            EXCEPTION_CHECK
1495                        }
1496                        if (kfDef.pszIcon) {
1497                            jstr = JNU_NewStringPlatform(env, kfDef.pszIcon);
1498                            if (jstr) {
1499                                env->SetObjectField(fld, field_icon, jstr);
1500                            }
1501                            EXCEPTION_CHECK
1502                        }
1503                        if (kfDef.pszSecurity) {
1504                            jstr = JNU_NewStringPlatform(env, kfDef.pszSecurity);
1505                            if (jstr) {
1506                                env->SetObjectField(fld, field_security, jstr);
1507                            }
1508                            EXCEPTION_CHECK
1509                        }
1510                        if (SUCCEEDED(StringFromCLSID(kfDef.ftidType, &guid))) {
1511                            jstr = JNU_NewStringPlatform(env, guid);
1512                            if (jstr) {
1513                                env->SetObjectField(fld, field_ftidType, jstr);
1514                            }
1515                            CoTaskMemFree(guid);
1516                            EXCEPTION_CHECK
1517                        }
1518                        env->SetIntField(fld, field_category, kfDef.category);
1519                        env->SetIntField(fld, field_defenitionFlags, kfDef.kfdFlags);
1520                        env->SetLongField(fld, field_attributes, kfDef.dwAttributes);
1521
1522                        LPWSTR folderPath = NULL;
1523                        if (SUCCEEDED(pFolder->GetPath(KF_FLAG_NO_ALIAS, &folderPath))
1524                                    && folderPath) {
1525                            jstr = JNU_NewStringPlatform(env, folderPath);
1526                            if (jstr) {
1527                                env->SetObjectField(fld, field_path, jstr);
1528                            }
1529                            CoTaskMemFree(folderPath);
1530                            EXCEPTION_CHECK
1531                        }
1532
1533                        IShellLibrary *plib = NULL;
1534                        hr = CoCreateInstance(CLSID_ShellLibrary, NULL,
1535                                         CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&plib));
1536                        if (SUCCEEDED(hr)) {
1537                            hr = plib->LoadLibraryFromKnownFolder(folderId, STGM_READWRITE);
1538                            if (SUCCEEDED(hr)) {
1539                                IShellItem *item = NULL;
1540                                hr = plib->GetDefaultSaveFolder(DSFT_DETECT,
1541                                        IID_PPV_ARGS(&item));
1542                                if (SUCCEEDED(hr) && item) {
1543                                    LPWSTR loc = NULL;
1544                                    hr = item->GetDisplayName(SIGDN_FILESYSPATH, &loc);
1545                                    if (SUCCEEDED(hr) && loc)
1546                                    {
1547                                        jstr = JNU_NewStringPlatform(env, loc);
1548                                        if (jstr) {
1549                                            env->SetObjectField(fld, field_saveLocation, jstr);
1550                                        }
1551                                        CoTaskMemFree(loc);
1552                                    }
1553                                    item->Release();
1554                                }
1555                            }
1556                            plib->Release();
1557                            EXCEPTION_CHECK
1558                        }
1559                        FreeKnownFolderDefinitionFields(&kfDef);
1560                    } catch (std::bad_alloc&) {
1561                        FreeKnownFolderDefinitionFields(&kfDef);
1562                        pFolder->Release();
1563                        CoTaskMemFree(pFoldersIds);
1564                        pkfm->Release();
1565                        throw;
1566                    }
1567                }
1568            }
1569            pFolder->Release();
1570        }
1571        CoTaskMemFree(pFoldersIds);
1572    }
1573    pkfm->Release();
1574    return result;
1575    CATCH_BAD_ALLOC_RET(NULL);
1576}
1577
1578} // extern "C"
1579