From 1061c1af2790679cddd911aec915cde3428e96b4 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Fri, 23 Oct 2015 16:24:52 -0700 Subject: [PATCH 01/12] Make sure the Structure constructors are always chained in, so QueryInterface et al don't crash the whole JVM --- .../src/com/sun/jna/platform/win32/Guid.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Guid.java b/contrib/platform/src/com/sun/jna/platform/win32/Guid.java index 7427dfbe39..a948ad3620 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Guid.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Guid.java @@ -38,7 +38,9 @@ public interface Guid { public static class GUID extends Structure { public static class ByValue extends GUID implements Structure.ByValue { - public ByValue() {} + public ByValue() { + super(); + } public ByValue(GUID guid) { super(guid.getPointer()); @@ -64,6 +66,7 @@ public static class ByReference extends GUID implements * Instantiates a new by reference. */ public ByReference() { + super(); } /** @@ -108,6 +111,7 @@ public ByReference(Pointer memory) { * Instantiates a new guid. */ public GUID() { + super(); } /** @@ -117,6 +121,7 @@ public GUID() { * the guid */ public GUID(GUID guid) { + super(); this.Data1 = guid.Data1; this.Data2 = guid.Data2; this.Data3 = guid.Data3; @@ -392,6 +397,7 @@ public static class ByReference extends GUID { * Instantiates a new by reference. */ public ByReference() { + super(); } /** @@ -411,7 +417,7 @@ public ByReference(GUID guid) { * the memory */ public ByReference(Pointer memory) { - + super(memory); } } @@ -419,6 +425,7 @@ public ByReference(Pointer memory) { * Instantiates a new clsid. */ public CLSID() { + super(); } /** @@ -451,7 +458,7 @@ public class REFIID extends IID { * Instantiates a new refiid. */ public REFIID() { - // TODO Auto-generated constructor stub + super(); } /** @@ -462,7 +469,6 @@ public REFIID() { */ public REFIID(Pointer memory) { super(memory); - // TODO Auto-generated constructor stub } /** @@ -473,9 +479,11 @@ public REFIID(Pointer memory) { */ public REFIID(byte[] data) { super(data); - // TODO Auto-generated constructor stub } + public REFIID(GUID guid) { + super(guid); + } } /** @@ -489,7 +497,7 @@ public class IID extends GUID { * Instantiates a new iid. */ public IID() { - // TODO Auto-generated constructor stub + super(); } /** @@ -500,7 +508,6 @@ public IID() { */ public IID(Pointer memory) { super(memory); - // TODO Auto-generated constructor stub } /** @@ -510,7 +517,6 @@ public IID(Pointer memory) { */ public IID(String iid) { super(iid); - // TODO Auto-generated constructor stub } /** @@ -521,7 +527,11 @@ public IID(String iid) { */ public IID(byte[] data) { super(data); - // TODO Auto-generated constructor stub } + + public IID(GUID guid) { + this(guid.toGuidString()); + } + } } \ No newline at end of file From 1d47c7e271f04609d5815e92c41117ab2fa54fcb Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Fri, 23 Oct 2015 16:25:24 -0700 Subject: [PATCH 02/12] Needed function to get My Computer shell object from Shell32 --- .../src/com/sun/jna/platform/win32/Shell32.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java index a2b839c505..cfdddec2e6 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java @@ -238,4 +238,21 @@ INT_PTR ShellExecute(HWND hwnd, String lpOperation, String lpFile, String lpPara * */ UINT_PTR SHAppBarMessage( DWORD dwMessage, APPBARDATA pData ); + + + /* + * SHGetSpecialFolderLocation function for getting PIDL reference to My Computer etc + * + * @param hwndOwner + * Reserved. + * @param nFolder + * A CSIDL value that identifies the folder of interest. + * @param ppidl + * A PIDL specifying the folder's location relative to the root of the namespace (the desktop). It is the responsibility of the calling application to free the returned IDList by using CoTaskMemFree. + * + * @return If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ + WinNT.HRESULT SHGetSpecialFolderLocation(WinDef.HWND hwndOwner, int nFolder, PointerByReference ppidl); + } From 0fb772458a9b860d34bb2739314c4b079eee56f0 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Fri, 23 Oct 2015 16:26:31 -0700 Subject: [PATCH 03/12] Shlwapi wrapper --- .../com/sun/jna/platform/win32/Shlwapi.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java b/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java new file mode 100644 index 0000000000..106f3b2cfd --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java @@ -0,0 +1,20 @@ +package com.sun.jna.platform.win32; + + +/* + * Copyright (c) 2015 L W Ahonen, All Rights Reserved + * + */ + +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Shell32; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.ptr.PointerByReference; +import com.sun.jna.win32.W32APIOptions; + +public interface Shlwapi extends WinNT { + Shlwapi INSTANCE = (Shlwapi) Native.loadLibrary("Shlwapi", Shlwapi.class, W32APIOptions.UNICODE_OPTIONS); + + HRESULT StrRetToStr(PointerByReference pstr, Pointer pidl, PointerByReference ppszName); +} From fa24e9dd7f5374efaea6885d49de83ec4db2edc4 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Fri, 23 Oct 2015 16:40:20 -0700 Subject: [PATCH 04/12] Necessary interfaces for enumerating items in My Computer --- .../jna/platform/win32/COM/IEnumIDList.java | 101 ++++++++++ .../jna/platform/win32/COM/IShellFolder.java | 182 ++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java new file mode 100644 index 0000000000..cf024c9111 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -0,0 +1,101 @@ +package com.sun.jna.platform.win32.COM; + +/* + * Copyright (c) 2015 L W Ahonen, All Rights Reserved + * + * + */ + +import com.sun.jna.Function; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Guid; +import com.sun.jna.platform.win32.Guid.IID; +import com.sun.jna.platform.win32.Guid.REFIID; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.platform.win32.WinNT.HRESULT; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +public interface IEnumIDList { + + /** + * The Constant IID_IDispatch. + */ + public final static IID IID_IEnumIDList = new IID( + "{000214F2-0000-0000-C000-000000000046}"); + + HRESULT QueryInterface( + Guid.GUID.ByReference riid, + PointerByReference ppvObject); + + int AddRef(); + + int Release(); + + HRESULT Next( + int celt, + PointerByReference rgelt, + IntByReference pceltFetched); + + HRESULT Skip( + int celt); + + HRESULT Reset(); + + HRESULT Clone( + PointerByReference ppenum); + + + public static class Converter { + public static IEnumIDList PointerToIEnumIDList(final PointerByReference ptr) { + final Pointer interfacePointer = ptr.getValue(); + final Pointer vTablePointer = interfacePointer.getPointer(0); + final Pointer[] vTable = new Pointer[7]; + vTablePointer.read(0, vTable, 0, 7); + return new IEnumIDList() { + + @Override + public WinNT.HRESULT QueryInterface(Guid.GUID.ByReference byValue, PointerByReference pointerByReference) { + Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION); + return new WinNT.HRESULT(f.invokeInt(new Object[]{interfacePointer, byValue, pointerByReference})); + } + + @Override + public int AddRef() { + Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION); + return f.invokeInt(new Object[]{interfacePointer}); + } + + public int Release() { + Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION); + return f.invokeInt(new Object[]{interfacePointer}); + } + + @Override + public HRESULT Next(int celt, PointerByReference rgelt, IntByReference pceltFetched) { + Function f = Function.getFunction(vTable[3], Function.ALT_CONVENTION); + return new HRESULT(f.invokeInt(new Object[]{interfacePointer, celt, rgelt, pceltFetched})); + } + + @Override + public HRESULT Skip(int celt) { + Function f = Function.getFunction(vTable[4], Function.ALT_CONVENTION); + return new HRESULT(f.invokeInt(new Object[]{interfacePointer, celt})); + } + + @Override + public HRESULT Reset() { + Function f = Function.getFunction(vTable[5], Function.ALT_CONVENTION); + return new HRESULT(f.invokeInt(new Object[]{interfacePointer})); + } + + @Override + public HRESULT Clone(PointerByReference ppenum) { + Function f = Function.getFunction(vTable[6], Function.ALT_CONVENTION); + return new HRESULT(f.invokeInt(new Object[]{interfacePointer, ppenum})); + } + }; + } + } +} diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java new file mode 100644 index 0000000000..049f779a97 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java @@ -0,0 +1,182 @@ +package com.sun.jna.platform.win32.COM; + +/* + * Copyright (c) 2015 L W Ahonen, All Rights Reserved + * + */ + +import com.sun.jna.Function; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.Guid; +import com.sun.jna.platform.win32.Guid.IID; +import com.sun.jna.platform.win32.Guid.REFIID; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.platform.win32.WinNT.HRESULT; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +public interface IShellFolder { + + /** The Constant IID_IDispatch. */ + public final static IID IID_ISHELLFOLDER = new IID( + "{000214E6-0000-0000-C000-000000000046}"); + + HRESULT QueryInterface( + REFIID riid, + PointerByReference ppvObject); + + int AddRef(); + + int Release(); + + HRESULT ParseDisplayName( + WinDef.HWND hwnd, + Pointer pbc, + String pszDisplayName, + IntByReference pchEaten, + PointerByReference ppidl, + IntByReference pdwAttributes); + + HRESULT EnumObjects( + WinDef.HWND hwnd, + int grfFlags, + PointerByReference ppenumIDList); + + HRESULT BindToObject( + Pointer pidl, + Pointer pbc, + REFIID riid, + PointerByReference ppv); + + HRESULT BindToStorage( + Pointer pidl, + Pointer pbc, + REFIID riid, + PointerByReference ppv); + + HRESULT CompareIDs( + WinDef.LPARAM lParam, + Pointer pidl1, + Pointer pidl2); + + HRESULT CreateViewObject( + WinDef.HWND hwndOwner, + REFIID riid, + PointerByReference ppv); + + HRESULT GetAttributesOf( + int cidl, + Pointer apidl, + IntByReference rgfInOut); + + HRESULT GetUIObjectOf( + WinDef.HWND hwndOwner, + int cidl, + Pointer apidl, + REFIID riid, + IntByReference rgfReserved, + PointerByReference ppv); + + HRESULT GetDisplayNameOf( + Pointer pidl, + int flags, + PointerByReference pName); + + HRESULT SetNameOf( + WinDef.HWND hwnd, + Pointer pidl, + String pszName, + int uFlags, + PointerByReference ppidlOut); + + + + public static class Converter + { + public static IShellFolder PointerToIShellFolder(final PointerByReference ptr) + { + final Pointer interfacePointer = ptr.getValue(); + final Pointer vTablePointer = interfacePointer.getPointer(0); + final Pointer[] vTable = new Pointer[13]; + vTablePointer.read(0, vTable, 0, 13); + return new IShellFolder() { + + @Override + public WinNT.HRESULT QueryInterface(REFIID byValue, PointerByReference pointerByReference) { + Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION); + return new WinNT.HRESULT(f.invokeInt(new Object[]{interfacePointer, byValue, pointerByReference})); + } + + @Override + public int AddRef() { + Function f = Function.getFunction(vTable[1], Function.ALT_CONVENTION); + return f.invokeInt(new Object[]{interfacePointer}); + } + + public int Release() { + Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION); + return f.invokeInt(new Object[]{interfacePointer}); + } + + @Override + public WinNT.HRESULT ParseDisplayName(WinDef.HWND hwnd, Pointer pbc, String pszDisplayName, IntByReference pchEaten, PointerByReference ppidl, IntByReference pdwAttributes) { + Function f = Function.getFunction(vTable[3], Function.ALT_CONVENTION); + return new WinNT.HRESULT(f.invokeInt(new Object[]{interfacePointer, hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes})); + } + + @Override + public WinNT.HRESULT EnumObjects(WinDef.HWND hwnd, int grfFlags, PointerByReference ppenumIDList) { + Function f = Function.getFunction(vTable[4], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, hwnd, grfFlags, ppenumIDList})); + } + + public WinNT.HRESULT BindToObject(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) { + Function f = Function.getFunction(vTable[5], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, pidl, pbc, riid, ppv})); + } + + @Override + public HRESULT BindToStorage(Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv) { + Function f = Function.getFunction(vTable[6], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, pidl, pbc, riid, ppv})); + } + + @Override + public HRESULT CompareIDs(WinDef.LPARAM lParam, Pointer pidl1, Pointer pidl2) { + Function f = Function.getFunction(vTable[7], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, lParam, pidl1, pidl2})); + } + + @Override + public HRESULT CreateViewObject(WinDef.HWND hwndOwner, REFIID riid, PointerByReference ppv) { + Function f = Function.getFunction(vTable[8], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, hwndOwner, riid, ppv})); + } + + @Override + public HRESULT GetAttributesOf(int cidl, Pointer apidl, IntByReference rgfInOut) { + Function f = Function.getFunction(vTable[9], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, cidl, apidl, rgfInOut})); + } + + @Override + public HRESULT GetUIObjectOf(WinDef.HWND hwndOwner, int cidl, Pointer apidl, REFIID riid, IntByReference rgfReserved, PointerByReference ppv) { + Function f = Function.getFunction(vTable[10], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, hwndOwner, cidl, apidl, riid, rgfReserved, ppv})); + } + + public WinNT.HRESULT GetDisplayNameOf(Pointer pidl, int flags, PointerByReference pName){ + Function f = Function.getFunction(vTable[11], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, pidl, flags, pName})); + } + + @Override + public HRESULT SetNameOf(WinDef.HWND hwnd, Pointer pidl, String pszName, int uFlags, PointerByReference ppidlOut) { + Function f = Function.getFunction(vTable[12], Function.ALT_CONVENTION); + return new WinNT.HRESULT( f.invokeInt(new Object[]{interfacePointer, hwnd, pidl, pszName, uFlags, ppidlOut})); + } + }; + } + } +} From 931cf53ff9ac5b365ffb6d3b6a73457542491b70 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Fri, 23 Oct 2015 16:41:17 -0700 Subject: [PATCH 05/12] An example into how to use the interfaces and functions in this pull request --- CHANGES.md | 1 + .../platform/win32/COM/IShellFolderTest.java | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+) mode change 100755 => 100644 CHANGES.md create mode 100644 contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java diff --git a/CHANGES.md b/CHANGES.md old mode 100755 new mode 100644 index b29988d4af..85105fd7df --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ Features * [#512](https://github.com/java-native-access/jna/pull/512): Make loading debug flags mutable [@lwahonen](https://github.com/lwahonen). * [#514](https://github.com/java-native-access/jna/pull/514): Added `host_processor_info` to `com.sun.jna.platform.mac.SystemB` - [@dbwiddis](https://github.com/dbwiddis). * [#519](https://github.com/java-native-access/jna/pull/519): Added JNA functional overview - [@twall](https://github.com/twall). +* [#524](https://github.com/java-native-access/jna/pull/524): IShellFolder interface plus necessary interfaces, and a sample for enumerating objects in My Computer - [@lwahonen](https://github.com/lwahonen). Bug Fixes --------- diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java new file mode 100644 index 0000000000..b6b0d691e0 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java @@ -0,0 +1,91 @@ +package com.sun.jna.platform.win32.COM; + +/* + * Copyright (c) 2015 L W Ahonen, All Rights Reserved + * + */ + + +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.*; +import com.sun.jna.ptr.PointerByReference; +import junit.framework.TestCase; + +public class IShellFolderTest extends TestCase { + + private IShellFolder psfMyComputer; + + public static WinNT.HRESULT BindToCsidl(int csidl, Guid.REFIID riid, PointerByReference ppv) { + WinNT.HRESULT hr; + PointerByReference pidl = new PointerByReference(); + hr = Shell32.INSTANCE.SHGetSpecialFolderLocation(null, csidl, pidl); + if (COMUtils.SUCCEEDED(hr)) { + PointerByReference psfDesktopPTR = new PointerByReference(); + hr = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR); + if (COMUtils.SUCCEEDED(hr)) { + IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR); + short cb = pidl.getValue().getShort(0); + if (cb != 0) { + hr = psfDesktop.BindToObject(pidl.getValue(), null, riid, ppv); + } else { + hr = psfDesktop.QueryInterface(riid, ppv); + } + psfDesktop.Release(); + } + Ole32.INSTANCE.CoTaskMemFree(pidl.getValue()); + } + return hr; + } + + public void setUp() throws Exception { + Ole32.INSTANCE.CoInitialize(null); + int CSIDL_DRIVES = 0x0011; + WinNT.HRESULT hr = Ole32.INSTANCE.CoInitialize(null); + if (COMUtils.SUCCEEDED(hr)) { + PointerByReference psfMyComputerPTR = new PointerByReference(Pointer.NULL); + hr = BindToCsidl(CSIDL_DRIVES, new Guid.REFIID(IShellFolder.IID_ISHELLFOLDER), psfMyComputerPTR); + if (COMUtils.SUCCEEDED(hr)) { + psfMyComputer = IShellFolder.Converter.PointerToIShellFolder(psfMyComputerPTR); + } + } + if(psfMyComputer == null) + throw new RuntimeException("Unable to create my computer shell object"); + } + + public void tearDown() throws Exception { + psfMyComputer.Release(); + Ole32.INSTANCE.CoUninitialize(); + } + + public void testEnumObjects() throws Exception { + PointerByReference peidlPTR = new PointerByReference(); + int SHCONTF_FOLDERS = 0x20; + int SHCONTF_NONFOLDERS = 0x40; + boolean sawNames=false; + + WinNT.HRESULT hr = psfMyComputer.EnumObjects(null, + SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, peidlPTR); + if (COMUtils.SUCCEEDED(hr)) { + IEnumIDList peidl = IEnumIDList.Converter.PointerToIEnumIDList(peidlPTR); + PointerByReference pidlItem = new PointerByReference(); + while (peidl.Next(1, pidlItem, null).intValue() == COMUtils.S_OK) { + PointerByReference sr = new PointerByReference(); + hr = psfMyComputer.GetDisplayNameOf(pidlItem.getValue(), 0, sr); + if (COMUtils.SUCCEEDED(hr)) { + PointerByReference pszName = new PointerByReference(); + hr = Shlwapi.INSTANCE.StrRetToStr(sr, pidlItem.getValue(), pszName); + if (COMUtils.SUCCEEDED(hr)) { + String wideString = pszName.getValue().getWideString(0); + if (wideString != null && wideString.length() > 0) + sawNames = true; + Ole32.INSTANCE.CoTaskMemFree(pszName.getValue()); + } + Ole32.INSTANCE.CoTaskMemFree(sr.getValue()); + } + Ole32.INSTANCE.CoTaskMemFree(pidlItem.getValue()); + } + peidl.Release(); + } + assertTrue(sawNames); + } +} \ No newline at end of file From 8fe525184034782915759be0b99aebd045766cf5 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Sat, 24 Oct 2015 13:22:07 -0700 Subject: [PATCH 06/12] Added assertions for COM success status --- .../platform/win32/COM/IShellFolderTest.java | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java index b6b0d691e0..f76876673d 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java @@ -1,10 +1,11 @@ package com.sun.jna.platform.win32.COM; /* - * Copyright (c) 2015 L W Ahonen, All Rights Reserved - * + * @author L W Ahonen, lwahonen@iki.fi */ +import junit.framework.TestCase; + import com.sun.jna.Pointer; import com.sun.jna.platform.win32.*; @@ -19,21 +20,19 @@ public static WinNT.HRESULT BindToCsidl(int csidl, Guid.REFIID riid, PointerByRe WinNT.HRESULT hr; PointerByReference pidl = new PointerByReference(); hr = Shell32.INSTANCE.SHGetSpecialFolderLocation(null, csidl, pidl); - if (COMUtils.SUCCEEDED(hr)) { - PointerByReference psfDesktopPTR = new PointerByReference(); - hr = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR); - if (COMUtils.SUCCEEDED(hr)) { - IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR); - short cb = pidl.getValue().getShort(0); - if (cb != 0) { - hr = psfDesktop.BindToObject(pidl.getValue(), null, riid, ppv); - } else { - hr = psfDesktop.QueryInterface(riid, ppv); - } - psfDesktop.Release(); - } - Ole32.INSTANCE.CoTaskMemFree(pidl.getValue()); + assertTrue(COMUtils.SUCCEEDED(hr)); + PointerByReference psfDesktopPTR = new PointerByReference(); + hr = Shell32.INSTANCE.SHGetDesktopFolder(psfDesktopPTR); + assertTrue(COMUtils.SUCCEEDED(hr)); + IShellFolder psfDesktop = IShellFolder.Converter.PointerToIShellFolder(psfDesktopPTR); + short cb = pidl.getValue().getShort(0); // See http://blogs.msdn.com/b/oldnewthing/archive/2011/08/30/10202076.aspx for explanation about this bit + if (cb != 0) { + hr = psfDesktop.BindToObject(pidl.getValue(), null, riid, ppv); + } else { + hr = psfDesktop.QueryInterface(riid, ppv); } + psfDesktop.Release(); + Ole32.INSTANCE.CoTaskMemFree(pidl.getValue()); return hr; } @@ -41,15 +40,11 @@ public void setUp() throws Exception { Ole32.INSTANCE.CoInitialize(null); int CSIDL_DRIVES = 0x0011; WinNT.HRESULT hr = Ole32.INSTANCE.CoInitialize(null); - if (COMUtils.SUCCEEDED(hr)) { - PointerByReference psfMyComputerPTR = new PointerByReference(Pointer.NULL); - hr = BindToCsidl(CSIDL_DRIVES, new Guid.REFIID(IShellFolder.IID_ISHELLFOLDER), psfMyComputerPTR); - if (COMUtils.SUCCEEDED(hr)) { - psfMyComputer = IShellFolder.Converter.PointerToIShellFolder(psfMyComputerPTR); - } - } - if(psfMyComputer == null) - throw new RuntimeException("Unable to create my computer shell object"); + assertTrue(COMUtils.SUCCEEDED(hr)); + PointerByReference psfMyComputerPTR = new PointerByReference(Pointer.NULL); + hr = BindToCsidl(CSIDL_DRIVES, new Guid.REFIID(IShellFolder.IID_ISHELLFOLDER), psfMyComputerPTR); + assertTrue(COMUtils.SUCCEEDED(hr)); + psfMyComputer = IShellFolder.Converter.PointerToIShellFolder(psfMyComputerPTR); } public void tearDown() throws Exception { @@ -61,31 +56,27 @@ public void testEnumObjects() throws Exception { PointerByReference peidlPTR = new PointerByReference(); int SHCONTF_FOLDERS = 0x20; int SHCONTF_NONFOLDERS = 0x40; - boolean sawNames=false; + boolean sawNames = false; WinNT.HRESULT hr = psfMyComputer.EnumObjects(null, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, peidlPTR); - if (COMUtils.SUCCEEDED(hr)) { - IEnumIDList peidl = IEnumIDList.Converter.PointerToIEnumIDList(peidlPTR); - PointerByReference pidlItem = new PointerByReference(); - while (peidl.Next(1, pidlItem, null).intValue() == COMUtils.S_OK) { - PointerByReference sr = new PointerByReference(); - hr = psfMyComputer.GetDisplayNameOf(pidlItem.getValue(), 0, sr); - if (COMUtils.SUCCEEDED(hr)) { - PointerByReference pszName = new PointerByReference(); - hr = Shlwapi.INSTANCE.StrRetToStr(sr, pidlItem.getValue(), pszName); - if (COMUtils.SUCCEEDED(hr)) { - String wideString = pszName.getValue().getWideString(0); - if (wideString != null && wideString.length() > 0) - sawNames = true; - Ole32.INSTANCE.CoTaskMemFree(pszName.getValue()); - } - Ole32.INSTANCE.CoTaskMemFree(sr.getValue()); - } - Ole32.INSTANCE.CoTaskMemFree(pidlItem.getValue()); - } - peidl.Release(); + assertTrue(COMUtils.SUCCEEDED(hr)); + IEnumIDList peidl = IEnumIDList.Converter.PointerToIEnumIDList(peidlPTR); + PointerByReference pidlItem = new PointerByReference(); + while (peidl.Next(1, pidlItem, null).intValue() == COMUtils.S_OK) { + PointerByReference sr = new PointerByReference(); + hr = psfMyComputer.GetDisplayNameOf(pidlItem.getValue(), 0, sr); + assertTrue(COMUtils.SUCCEEDED(hr)); + PointerByReference pszName = new PointerByReference(); + hr = Shlwapi.INSTANCE.StrRetToStr(sr, pidlItem.getValue(), pszName); + assertTrue(COMUtils.SUCCEEDED(hr)); + String wideString = pszName.getValue().getWideString(0); + if (wideString != null && wideString.length() > 0) + sawNames = true; + Ole32.INSTANCE.CoTaskMemFree(pszName.getValue()); + Ole32.INSTANCE.CoTaskMemFree(pidlItem.getValue()); } - assertTrue(sawNames); + peidl.Release(); + assertTrue(sawNames); // We should see at least one item with a name } } \ No newline at end of file From 218271b6e671e654afbe951f4317ce5c81a43056 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Sat, 24 Oct 2015 13:22:51 -0700 Subject: [PATCH 07/12] Clarified changes.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 85105fd7df..d44ee68321 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ Features * [#512](https://github.com/java-native-access/jna/pull/512): Make loading debug flags mutable [@lwahonen](https://github.com/lwahonen). * [#514](https://github.com/java-native-access/jna/pull/514): Added `host_processor_info` to `com.sun.jna.platform.mac.SystemB` - [@dbwiddis](https://github.com/dbwiddis). * [#519](https://github.com/java-native-access/jna/pull/519): Added JNA functional overview - [@twall](https://github.com/twall). -* [#524](https://github.com/java-native-access/jna/pull/524): IShellFolder interface plus necessary interfaces, and a sample for enumerating objects in My Computer - [@lwahonen](https://github.com/lwahonen). +* [#524](https://github.com/java-native-access/jna/pull/524): Added IShellFolder interface plus necessary utility functions to Windows platform, and a sample for enumerating objects in My Computer - [@lwahonen](https://github.com/lwahonen). Bug Fixes --------- From e792f2f95a4b43c15db5cd932dd9b76b9adf3832 Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Sat, 24 Oct 2015 13:23:24 -0700 Subject: [PATCH 08/12] Added documentation --- .../com/sun/jna/platform/win32/Shlwapi.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java b/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java index 106f3b2cfd..b0cbc1ce2b 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java @@ -1,9 +1,7 @@ package com.sun.jna.platform.win32; - /* - * Copyright (c) 2015 L W Ahonen, All Rights Reserved - * + * @author L W Ahonen, lwahonen@iki.fi */ import com.sun.jna.Native; @@ -13,8 +11,27 @@ import com.sun.jna.ptr.PointerByReference; import com.sun.jna.win32.W32APIOptions; -public interface Shlwapi extends WinNT { +public interface Shlwapi extends WinNT { Shlwapi INSTANCE = (Shlwapi) Native.loadLibrary("Shlwapi", Shlwapi.class, W32APIOptions.UNICODE_OPTIONS); + + /** + * Takes an STRRET structure returned by IShellFolder::GetDisplayNameOf and returns a pointer + * to an allocated string containing the display name. + * + * @param pstr + * A pointer to the STRRET structure. When the function returns, + * this pointer will no longer be valid. + * @param pidl + * A pointer to the item's ITEMIDLIST structure. This value can be NULL. + * + * @param ppszName + * A pointer to an allocated string containing the result. StrRetToStr allocates + * memory for this string with CoTaskMemAlloc. You should free the string + * with CoTaskMemFree when it is no longer needed. + * + * @return If this function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + */ + HRESULT StrRetToStr(PointerByReference pstr, Pointer pidl, PointerByReference ppszName); } From 7bd556edb0d890241dbe3f8b2a2c8e3c5d5b454b Mon Sep 17 00:00:00 2001 From: Lauri W Ahonen Date: Sat, 24 Oct 2015 13:24:09 -0700 Subject: [PATCH 09/12] Copyright notice replaced with a author tag --- .../src/com/sun/jna/platform/win32/COM/IEnumIDList.java | 4 +--- .../src/com/sun/jna/platform/win32/COM/IShellFolder.java | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java index cf024c9111..53b69172bd 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -1,9 +1,7 @@ package com.sun.jna.platform.win32.COM; /* - * Copyright (c) 2015 L W Ahonen, All Rights Reserved - * - * + * @author L W Ahonen, lwahonen@iki.fi */ import com.sun.jna.Function; diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java index 049f779a97..eff0dabacd 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java @@ -1,8 +1,7 @@ package com.sun.jna.platform.win32.COM; /* - * Copyright (c) 2015 L W Ahonen, All Rights Reserved - * + * @author L W Ahonen, lwahonen@iki.fi */ import com.sun.jna.Function; From d81cf89536f6c6d940020657f1e040f47afd6c82 Mon Sep 17 00:00:00 2001 From: L W Ahonen Date: Thu, 3 Dec 2015 20:57:37 -0800 Subject: [PATCH 10/12] Add documentation to IEnumIDList --- .../jna/platform/win32/COM/IEnumIDList.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java index 53b69172bd..0f83cb09d1 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -31,20 +31,78 @@ HRESULT QueryInterface( int Release(); + /* + Retrieves the specified number of item identifiers in the enumeration sequence and advances the current position by the number of items retrieved. + * @param celt + * The number of elements in the array referenced by the rgelt parameter. + * @param rgelt + * The address of a pointer to an array of ITEMIDLIST pointers that receive the item identifiers. + * The implementation must allocate these item identifiers using CoTaskMemAlloc. + * The calling application is responsible for freeing the item identifiers using CoTaskMemFree. + * The ITEMIDLIST structures returned in the array are relative to the IShellFolder being enumerated. + * @param pceltFetched + * A pointer to a value that receives a count of the item identifiers actually returned in rgelt. + * The count can be smaller than the value specified in the celt parameter. This parameter can be NULL on entry only if celt = 1, + * because in that case the method can only retrieve one (S_OK) or zero (S_FALSE) items. + * + * @return HRESULT + * Returns S_OK if the method successfully retrieved the requested celt elements. + * This method only returns S_OK if the full count of requested items are successfully retrieved. + * S_FALSE indicates that more items were requested than remained in the enumeration. + * The value pointed to by the pceltFetched parameter specifies the actual number of items retrieved. + * Note that the value will be 0 if there are no more items to retrieve. + * Returns a COM-defined error value otherwise. + * + * If this method returns a Component Object Model (COM) error code (as determined by the COMUtils.FAILED macro), + * then no entries in the rgelt array are valid on exit. If this method returns a success code (such as S_OK or S_FALSE), + * then the ULONG pointed to by the pceltFetched parameter determines how many entries in the rgelt array are valid on exit. + * + * The distinction is important in the case where celt > 1. For example, if you pass celt=10 and there are only 3 elements left, + * *pceltFetched will be 3 and the method will return S_FALSE meaning that you reached the end of the file. + * The three fetched elements will be stored into rgelt and are valid. + */ HRESULT Next( int celt, PointerByReference rgelt, IntByReference pceltFetched); + /** + * Skips the specified number of elements in the enumeration sequence. + * @param celt + * The number of item identifiers to skip. + * @return HRESULT + * Returns S_OK if successful, or a COM-defined error value otherwise. + */ HRESULT Skip( int celt); + /** + * Returns to the beginning of the enumeration sequence. + * @return HRESULT + * Returns S_OK if successful, or a COM-defined error value otherwise. + */ + HRESULT Reset(); + /** + * Creates a new item enumeration object with the same contents and state as the current one. + * @param ppenum + * The address of a pointer to the new enumeration object. The calling application must eventually free the new object by calling its Release member function. + * @return HRESULT + * Returns S_OK if successful, or a COM-defined error value otherwise. + */ HRESULT Clone( PointerByReference ppenum); + /* + Use this like: + + PointerByReference pbr=new PointerByReference(); + HRESULT result=SomeCOMObject.QueryInterface(IID_IEnumIDList, pbr); + if(COMUtils.SUCCEEDED(result)) IENumIDList eil=IEnumIDList.Converter.PointerToIEnumIDList(pbr); + + */ public static class Converter { public static IEnumIDList PointerToIEnumIDList(final PointerByReference ptr) { final Pointer interfacePointer = ptr.getValue(); From e24f18849d2e675382a7aac376fc8612860f8fc0 Mon Sep 17 00:00:00 2001 From: L W Ahonen Date: Thu, 3 Dec 2015 21:08:48 -0800 Subject: [PATCH 11/12] Document the IUnknown methods too --- .../jna/platform/win32/COM/IEnumIDList.java | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java index 0f83cb09d1..7082d17fb1 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -18,17 +18,89 @@ public interface IEnumIDList { /** - * The Constant IID_IDispatch. + * The interface IID for QueryInterface et al */ public final static IID IID_IEnumIDList = new IID( "{000214F2-0000-0000-C000-000000000046}"); + /** + * + * Retrieves pointers to the supported interfaces on an object. + * This method calls IUnknown::AddRef on the pointer it returns. + * + * @param riid + * The identifier of the interface being requested. + * + * @param ppvObject + * The address of a pointer variable that receives the interface pointer requested in the riid parameter. Upon successful + * return, *ppvObject contains the requested interface pointer to the object. If the object does not support the + * interface, *ppvObject is set to NULL. + * + * @return + * This method returns S_OK if the interface is supported, and E_NOINTERFACE otherwise. If ppvObject is NULL, this method returns E_POINTER. + * For any one object, a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. + * This enables a client to determine whether two pointers point to the same component by calling QueryInterfacewith IID_IUnknown + * and comparing the results. It is specifically not the case that queries for interfaces other than IUnknown (even the same interface + * through the same pointer) must return the same pointer value. + * + * There are four requirements for implementations of QueryInterface (In these cases, "must succeed" means "must succeed barring + * catastrophic failure."): + * The set of interfaces accessible on an object through QueryInterface must be static, not dynamic. This means that if a call + * toQueryInterface for a pointer to a specified interface succeeds the first time, it must succeed again, and if it fails + * the first time, it must fail on all subsequent queries.
 + * + * It must be reflexive: if a client holds a pointer to an interface on an object, and queries for that interface, the call must succeed.
 + * + * It must be symmetric: if a client holding a pointer to one interface queries successfully for another, a query through + * the obtained pointer for the first interface must succeed.
 + * + * It must be transitive: if a client holding a pointer to one interface queries successfully for a second, and through that + * pointer queries successfully for a third interface, a query for the first interface through the pointer for the + * third interface must succeed.
 + * Notes to Implementers + * Implementations of QueryInterface must never check ACLs. The main reason for this rule is that COM requires that an object supporting a + * particular interface always return success when queried for that interface. Another reason is that checking ACLs on QueryInterface + * does not provide any real security because any client who has access to a particular interface can hand it directly to another + * client without any calls back to the server. Also, because COM caches interface pointers, it does not callQueryInterface on + * the server every time a client does a query. + */ HRESULT QueryInterface( Guid.GUID.ByReference riid, PointerByReference ppvObject); + /** + * + * Increments the reference count for an interface on an object. This method should be called for every new copy of a pointer to an interface on an object. + * @return + * The method returns the new reference count. This value is intended to be used only for test purposes. + * + * Objects use a reference counting mechanism to ensure that the lifetime of the object includes the lifetime of references to it. You use AddRef + * to stabilize a copy of an interface pointer. It can also be called when the life of a cloned pointer must extend beyond the + * lifetime of the original pointer. The cloned pointer must be released by calling IUnknown::Release. + * + * The internal reference counter that AddRef maintains should be a 32-bit unsigned integer. + * Notes to Callers + * Call this method for every new copy of an interface pointer that you make. For example, if you are passing a copy of a pointer + * back from a method, you must call AddRef on that pointer. You must also call AddRef on a pointer before passing it as an in-out + * parameter to a method; the method will call IUnknown::Release before copying the out-value on top of it. + */ int AddRef(); + /** + * Decrements the reference count for an interface on an object. + * + * @return + * The method returns the new reference count. This value is intended to be used only for test purposes. + * + * When the reference count on an object reaches zero, Release must cause the interface pointer to free itself. When the released + * pointer is the only existing reference to an object (whether the object supports single or multiple interfaces), the + * implementation must free the object. + * + * Note that aggregation of objects restricts the ability to recover interface pointers. + * Notes to Callers + * Call this method when you no longer need to use an interface pointer. If you are writing a method that takes an in-out + * parameter, call Release on the pointer you are passing in before copying the out-value on top of it. + */ int Release(); /* From 0ab0660b826e99dbf6b75ed8520dcbd8f289dc55 Mon Sep 17 00:00:00 2001 From: L W Ahonen Date: Thu, 3 Dec 2015 21:43:06 -0800 Subject: [PATCH 12/12] Documentation for IShellFolder too --- .../jna/platform/win32/COM/IEnumIDList.java | 4 +- .../jna/platform/win32/COM/IShellFolder.java | 341 +++++++++++++++++- 2 files changed, 341 insertions(+), 4 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java index 7082d17fb1..7887816a35 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -65,7 +65,7 @@ public interface IEnumIDList { * the server every time a client does a query. */ HRESULT QueryInterface( - Guid.GUID.ByReference riid, + REFIID riid, PointerByReference ppvObject); /** @@ -184,7 +184,7 @@ public static IEnumIDList PointerToIEnumIDList(final PointerByReference ptr) { return new IEnumIDList() { @Override - public WinNT.HRESULT QueryInterface(Guid.GUID.ByReference byValue, PointerByReference pointerByReference) { + public WinNT.HRESULT QueryInterface(REFIID byValue, PointerByReference pointerByReference) { Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION); return new WinNT.HRESULT(f.invokeInt(new Object[]{interfacePointer, byValue, pointerByReference})); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java index eff0dabacd..4464eaa9de 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java @@ -17,18 +17,134 @@ public interface IShellFolder { - /** The Constant IID_IDispatch. */ + + /** + * The interface IID for QueryInterface et al + */ public final static IID IID_ISHELLFOLDER = new IID( "{000214E6-0000-0000-C000-000000000046}"); + /** + * + * Retrieves pointers to the supported interfaces on an object. + * This method calls IUnknown::AddRef on the pointer it returns. + * + * @param riid + * The identifier of the interface being requested. + * + * @param ppvObject + * The address of a pointer variable that receives the interface pointer requested in the riid parameter. Upon successful + * return, *ppvObject contains the requested interface pointer to the object. If the object does not support the + * interface, *ppvObject is set to NULL. + * + * @return + * This method returns S_OK if the interface is supported, and E_NOINTERFACE otherwise. If ppvObject is NULL, this method returns E_POINTER. + * For any one object, a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. + * This enables a client to determine whether two pointers point to the same component by calling QueryInterfacewith IID_IUnknown + * and comparing the results. It is specifically not the case that queries for interfaces other than IUnknown (even the same interface + * through the same pointer) must return the same pointer value. + * + * There are four requirements for implementations of QueryInterface (In these cases, "must succeed" means "must succeed barring + * catastrophic failure."): + * The set of interfaces accessible on an object through QueryInterface must be static, not dynamic. This means that if a call + * toQueryInterface for a pointer to a specified interface succeeds the first time, it must succeed again, and if it fails + * the first time, it must fail on all subsequent queries.
 + * + * It must be reflexive: if a client holds a pointer to an interface on an object, and queries for that interface, the call must succeed.
 + * + * It must be symmetric: if a client holding a pointer to one interface queries successfully for another, a query through + * the obtained pointer for the first interface must succeed.
 + * + * It must be transitive: if a client holding a pointer to one interface queries successfully for a second, and through that + * pointer queries successfully for a third interface, a query for the first interface through the pointer for the + * third interface must succeed.
 + * Notes to Implementers + * Implementations of QueryInterface must never check ACLs. The main reason for this rule is that COM requires that an object supporting a + * particular interface always return success when queried for that interface. Another reason is that checking ACLs on QueryInterface + * does not provide any real security because any client who has access to a particular interface can hand it directly to another + * client without any calls back to the server. Also, because COM caches interface pointers, it does not callQueryInterface on + * the server every time a client does a query. + */ HRESULT QueryInterface( REFIID riid, PointerByReference ppvObject); + /** + * + * Increments the reference count for an interface on an object. This method should be called for every new copy of a pointer to an interface on an object. + * @return + * The method returns the new reference count. This value is intended to be used only for test purposes. + * + * Objects use a reference counting mechanism to ensure that the lifetime of the object includes the lifetime of references to it. You use AddRef + * to stabilize a copy of an interface pointer. It can also be called when the life of a cloned pointer must extend beyond the + * lifetime of the original pointer. The cloned pointer must be released by calling IUnknown::Release. + * + * The internal reference counter that AddRef maintains should be a 32-bit unsigned integer. + * Notes to Callers + * Call this method for every new copy of an interface pointer that you make. For example, if you are passing a copy of a pointer + * back from a method, you must call AddRef on that pointer. You must also call AddRef on a pointer before passing it as an in-out + * parameter to a method; the method will call IUnknown::Release before copying the out-value on top of it. + */ int AddRef(); + /** + * Decrements the reference count for an interface on an object. + * + * @return + * The method returns the new reference count. This value is intended to be used only for test purposes. + * + * When the reference count on an object reaches zero, Release must cause the interface pointer to free itself. When the released + * pointer is the only existing reference to an object (whether the object supports single or multiple interfaces), the + * implementation must free the object. + * + * Note that aggregation of objects restricts the ability to recover interface pointers. + * Notes to Callers + * Call this method when you no longer need to use an interface pointer. If you are writing a method that takes an in-out + * parameter, call Release on the pointer you are passing in before copying the out-value on top of it. + */ int Release(); + /** + * Translates the display name of a file object or a folder into an item identifier list + * + * @param hwnd + * A window handle. The client should provide a window handle if it displays a dialog or message box. Otherwise set hwnd to NULL. + * + * @param pbc + * Optional. A pointer to a bind context used to pass parameters as inputs and outputs to the parsing function. These passed parameters + * are often specific to the data source and are documented by the data source owners. For example, the file system data source accepts + * the name being parsed (as a WIN32_FIND_DATA structure), using the STR_FILE_SYS_BIND_DATA bind context parameter. + * STR_PARSE_PREFER_FOLDER_BROWSING can be passed to indicate that URLs are parsed using the file system data source when possible. + * Construct a bind context object using CreateBindCtx and populate the values using IBindCtx::RegisterObjectParam. See Bind Context + * String Keys for a complete list of these. + * + * If no data is being passed to or received from the parsing function, this value can be NULL. + * + * @param pszDisplayName + * A null-terminated Unicode string with the display name. Because each Shell folder defines its own parsing syntax, the + * form this string can take may vary. The desktop folder, for instance, accepts paths such as "C:\My Docs\My File.txt". + * It also will accept references to items in the namespace that have a GUID associated with them using the "::{GUID}" syntax. + * For example, to retrieve a fully qualified identifier list for the control panel from the desktop folder, you can use the following: + * "::{CLSID for Control Panel}\::{CLSID for printers folder}" + * + * @param pchEaten + * A pointer to a ULONG value that receives the number of characters of the display name that was parsed. If your application + * does not need this information, set pchEaten to NULL, and no value will be returned. + * + * @param ppidl + * When this method returns, contains a pointer to the PIDL for the object. The returned item identifier list specifies the item + * relative to the parsing folder. If the object associated with pszDisplayName is within the parsing folder, the returned item + * identifier list will contain only one SHITEMID structure. If the object is in a subfolder of the parsing folder, the returned + * item identifier list will contain multiple SHITEMID structures. If an error occurs, NULL is returned in this address. + * + * When it is no longer needed, it is the responsibility of the caller to free this resource by calling CoTaskMemFree. + * + * @param pdwAttributes + * The value used to query for file attributes. If not used, it should be set to NULL. To query for one or more attributes, initialize + * this parameter with the SFGAO flags that represent the attributes of interest. On return, those attributes that are true and were requested will be set. + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + */ HRESULT ParseDisplayName( WinDef.HWND hwnd, Pointer pbc, @@ -37,38 +153,212 @@ HRESULT ParseDisplayName( PointerByReference ppidl, IntByReference pdwAttributes); + /** + * Enables a client to determine the contents of a folder by creating an item identifier enumeration object and returning its IEnumIDList interface. + * The methods supported by that interface can then be used to enumerate the folder's contents. + * + * @param hwnd + * If user input is required to perform the enumeration, this window handle should be used by the enumeration object as the parent window + * to take user input. An example would be a dialog box to ask for a password or prompt the user to insert a CD or floppy disk. + * If hwndOwner is set to NULL, the enumerator should not post any messages, and if user input is required, it should silently fail. + * + * @param grfFlags + * Flags indicating which items to include in the enumeration. For a list of possible values, see the SHCONTF enumerated type. + * + * @param ppenumIDList + * The address that receives a pointer to the IEnumIDList interface of the enumeration object created by this method. + * If an error occurs or no suitable subobjects are found, ppenumIDList is set to NULL. + * + * @return + * Returns S_OK if successful, or an error value otherwise. Some implementations may also return S_FALSE, indicating that there + * are no children matching the grfFlags that were passed in. If S_FALSE is returned, ppenumIDList is set to NULL. + * + */ HRESULT EnumObjects( WinDef.HWND hwnd, int grfFlags, PointerByReference ppenumIDList); + /** + * + * Retrieves a handler, typically the Shell folder object that implements IShellFolder for a particular item. Optional + * parameters that control the construction of the handler are passed in the bind context. + * @param pidl + * + * The address of an ITEMIDLIST structure (PIDL) that identifies the subfolder. This value can refer to an item at any level below + * the parent folder in the namespace hierarchy. The structure contains one or more SHITEMID structures, followed by a terminating NULL. + * + * @param pbc + * + * A pointer to an IBindCtx interface on a bind context object that can be used to pass parameters to the construction of the handler. + * If this parameter is not used, set it to NULL. Because support for this parameter is optional for folder object implementations, + * some folders may not support the use of bind contexts. + * Information that can be provided in the bind context includes a BIND_OPTS structure that includes a grfMode member that indicates + * the access mode when binding to a stream handler. Other parameters can be set and discovered using IBindCtx::RegisterObjectParam + * and IBindCtx::GetObjectParam. + * + * @param riid + * The identifier of the interface to return. This may be IID_IShellFolder, IID_IStream, or any other interface that identifies a particular handler. + * + * @param ppv + * When this method returns, contains the address of a pointer to the requested interface. If an error occurs, a NULL pointer is returned at this address. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT BindToObject( Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv); + /** + * Requests a pointer to an object's storage interface. + * @param pidl + * The address of an ITEMIDLIST structure that identifies the subfolder relative to its parent folder. The structure must contain exactly one SHITEMID structure followed by a terminating zero. + * + * @param pbc + * The optional address of an IBindCtx interface on a bind context object to be used during this operation. If this parameter is + * not used, set it to NULL. Because support for pbc is optional for folder object implementations, some folders may not support the use of bind contexts. + * + * @param riid + * The IID of the requested storage interface. To retrieve an IStream, IStorage, or IPropertySetStorage interface pointer, set + * riid to IID_IStream, IID_IStorage, or IID_IPropertySetStorage, respectively. + * + * @param ppv + * The address that receives the interface pointer specified by riid. If an error occurs, a NULL pointer is returned in this address. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT BindToStorage( Pointer pidl, Pointer pbc, REFIID riid, PointerByReference ppv); + /** + * Determines the relative order of two file objects or folders, given their item identifier lists. + * @param lParam + * A value that specifies how the comparison should be performed. + * The lower sixteen bits of lParam define the sorting rule. Most applications set the sorting rule to the default value of zero, indicating that the + * two items should be compared by name. The system does not define any other sorting rules. Some folder objects might allow calling applications to + * use the lower sixteen bits of lParam to specify folder-specific sorting rules. The rules and their associated lParam values are defined by the folder. + * + * When the system folder view object calls IShellFolder::CompareIDs, the lower sixteen bits of lParam are used to specify the column to be used for + * the comparison. + * The upper sixteen bits of lParam are used for flags that modify the sorting rule. The system currently defines these modifier flags. + * + * SHCIDS_ALLFIELDS + * Version 5.0. Compare all the information contained in the ITEMIDLIST structure, not just the display names. This flag is valid only for folder objects that support + * the IShellFolder2 interface. For instance, if the two items are files, the folder should compare their names, sizes, file times, attributes, and any other information + * in the structures. If this flag is set, the lower sixteen bits of lParam must be zero. + * + * SHCIDS_CANONICALONLY + * Version 5.0. When comparing by name, compare the system names but not the display names. When this flag is passed, the two items are compared by whatever criteria the + * Shell folder determines are most efficient, as long as it implements a consistent sort function. This flag is useful when comparing for equality or when the results of + * the sort are not displayed to the user. This flag cannot be combined with other flags. + * + * @param pidl1 + * A pointer to the first item's ITEMIDLIST structure. It will be relative to the folder. This ITEMIDLIST structure can contain more than one + * element; therefore, the entire structure must be compared, not just the first element. + * + * @param pidl2 + * A pointer to the second item's ITEMIDLIST structure. It will be relative to the folder. This ITEMIDLIST structure can contain more than one + * element; therefore, the entire structure must be compared, not just the first element. + * + * @return + * If this method is successful, the CODE field of the HRESULT contains one of the following values. For information regarding the extraction of + * the CODE field from the returned HRESULT, see Remarks. If this method is unsuccessful, it returns a COM error code. + * Negative + * A negative return value indicates that the first item should precede the second (pidl1 < pidl2). + * Positive + * A positive return value indicates that the first item should follow the second (pidl1 > pidl2). + * Zero + * A return value of zero indicates that the two items are the same (pidl1 = pidl2). + * Use the HRESULT_CODE macro to extract the CODE field from the HRESULT, then cast the result as a short. + * #define HRESULT_CODE(hr) ((hr) & 0xFFFF) + * + */ HRESULT CompareIDs( WinDef.LPARAM lParam, Pointer pidl1, Pointer pidl2); + + /** + * Requests an object that can be used to obtain information from or interact with a folder object. + * + * @param hwndOwner + * A handle to the owner window. If you have implemented a custom folder view object, your folder view window should be created as a child of hwndOwner. + * + * @param riid + * A reference to the IID of the interface to retrieve through ppv, typically IID_IShellView. + * + * @param ppv + * When this method returns successfully, contains the interface pointer requested in riid. This is typically IShellView. See the Remarks section for more details. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT CreateViewObject( WinDef.HWND hwndOwner, REFIID riid, PointerByReference ppv); + /** + * Gets the attributes of one or more file or folder objects contained in the object represented by IShellFolder. + * + * @param cidl + * The number of items from which to retrieve attributes. + * + * @param apidl + * The address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies an item relative to the parent folder. + * Each ITEMIDLIST structure must contain exactly one SHITEMID structure followed by a terminating zero. + * + * @param rgfInOut + * Pointer to a single ULONG value that, on entry, contains the bitwise SFGAO attributes that the calling application is requesting. On + * exit, this value contains the requested attributes that are common to all of the specified items. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT GetAttributesOf( int cidl, Pointer apidl, IntByReference rgfInOut); + /** + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + * @param hwndOwner + * A handle to the owner window that the client should specify if it displays a dialog box or message box. + * + * @param cidl + * The number of file objects or subfolders specified in the apidl parameter. + * + * @param apidl + * The address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to + * the parent folder. Each item identifier list must contain exactly one SHITEMID structure followed by a terminating zero. + * + * @param riid + * A reference to the IID of the interface to retrieve through ppv. This can be any valid interface identifier that can be created for an + * item. The most common identifiers used by the Shell are listed in the comments at the end of this reference. + * + * @param rgfReserved + * Reserved. + * + * @param ppv + * When this method returns successfully, contains the interface pointer requested in riid. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT GetUIObjectOf( WinDef.HWND hwndOwner, int cidl, @@ -77,11 +367,53 @@ HRESULT GetUIObjectOf( IntByReference rgfReserved, PointerByReference ppv); + /** + * Retrieves the display name for the specified file object or subfolder. + * + * @param pidl + * PIDL that uniquely identifies the file object or subfolder relative to the parent folder. + * + * @param flags + * Flags used to request the type of display name to return. For a list of possible values, see the SHGDNF enumerated type. + * + * @param pName + * When this method returns, contains a pointer to a STRRET structure in which to return the display name. The type of name returned in this structure can be the requested type, but the Shell folder might return a different type. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * It is the caller's responsibility to free resources allocated by this function. + * + */ HRESULT GetDisplayNameOf( Pointer pidl, int flags, PointerByReference pName); + /** + * Sets the display name of a file object or subfolder, changing the item identifier in the process. + * + * @param hwnd + * A handle to the owner window of any dialog or message box that the client displays. + * + * @param pidl + * A pointer to an ITEMIDLIST structure that uniquely identifies the file object or subfolder relative to the parent folder. + * The structure must contain exactly one SHITEMID structure followed by a terminating zero. + * + * @param pszName + * A pointer to a null-terminated string that specifies the new display name. + * + * @param uFlags + * Flags that indicate the type of name specified by the pszName parameter. For a list of possible values and combinations of values, see SHGDNF. + * + * @param ppidlOut + * Optional. If specified, the address of a pointer to an ITEMIDLIST structure that receives the ITEMIDLIST of the renamed item. The + * caller requests this value by passing a non-null ppidlOut. Implementations of IShellFolder::SetNameOf must return a pointer to the + * new ITEMIDLIST in the ppidlOut parameter. + * + * @return + * If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + * + */ HRESULT SetNameOf( WinDef.HWND hwnd, Pointer pidl, @@ -89,7 +421,12 @@ HRESULT SetNameOf( int uFlags, PointerByReference ppidlOut); - + /* + Use this like: + PointerByReference pbr=new PointerByReference(); + HRESULT result=SomeCOMObject.QueryInterface(IID_ISHELLFOLDER, pbr); + if(COMUtils.SUCCEEDED(result)) IShellFolder isf=IShellFolder.Converter.PointerToIShellFolder(pbr); + */ public static class Converter {