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