diff --git a/CHANGES.md b/CHANGES.md old mode 100755 new mode 100644 index 75b57b3653..76a73fcad9 --- a/CHANGES.md +++ b/CHANGES.md @@ -21,6 +21,7 @@ Features * [#545](https://github.com/java-native-access/jna/pull/545): Added `EnumResourceTypes` and `EnumResourceNames` to `com.sun.jna.platform.win32.Kernel32` - [@mlfreeman2](https://github.com/mlfreeman2). * [#547](https://github.com/java-native-access/jna/pull/547): Added `GetSystemTimes` to `com.sun.jna.platform.win32.Kernel32` - [@dbwiddis](https://github.com/dbwiddis). * [#548](https://github.com/java-native-access/jna/pull/548): Return 64-bit unsigned integer from `com.sun.jna.platform.win32.WinBase.FILETIME` - [@dbwiddis](https://github.com/dbwiddis). +* [#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 --------- 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..7887816a35 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java @@ -0,0 +1,229 @@ +package com.sun.jna.platform.win32.COM; + +/* + * @author L W Ahonen, lwahonen@iki.fi + */ + +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 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( + 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(); + + /* + 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(); + 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(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 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..4464eaa9de --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/IShellFolder.java @@ -0,0 +1,518 @@ +package com.sun.jna.platform.win32.COM; + +/* + * @author L W Ahonen, lwahonen@iki.fi + */ + +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 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, + String pszDisplayName, + IntByReference pchEaten, + 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, + Pointer apidl, + REFIID riid, + 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, + String pszName, + 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 + { + 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})); + } + }; + } + } +} 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 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 1f98925861..66e9fc2d24 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java @@ -274,51 +274,66 @@ INT_PTR ShellExecute(HWND hwnd, String lpOperation, String lpFile, String lpPara */ UINT_PTR SHAppBarMessage( DWORD dwMessage, APPBARDATA pData ); - /** - * Empties the Recycle Bin on the specified drive. - * - * @param hwnd - * A handle to the parent window of any dialog boxes that might - * be displayed during the operation.
- * This parameter can be NULL. - * @param pszRootPath - * a null-terminated string of maximum length MAX_PATH that - * contains the path of the root
- * drive on which the Recycle Bin is located. This parameter can - * contain a string formatted with the drive,
- * folder, and subfolder names, for example c:\windows\system\, - * etc. It can also contain an empty string or
- * NULL. If this value is an empty string or NULL, all Recycle - * Bins on all drives will be emptied. - * @param dwFlags - * a bitwise combination of SHERB_NOCONFIRMATION, - * SHERB_NOPROGRESSUI and SHERB_NOSOUND.
- * @return Returns S_OK (0) if successful, or a COM-defined error value - * otherwise.
- */ - int SHEmptyRecycleBin(HANDLE hwnd, String pszRootPath, int dwFlags); - - /** - * @param lpExecInfo - *

- * Type: SHELLEXECUTEINFO* - *

- *

- * A pointer to a - * SHELLEXECUTEINFO - * structure that contains and receives information - * about the application being executed. - *

- * @return - *

- * Returns TRUE if successful; otherwise, - * FALSE. Call - * GetLastError - * for extended error information. - *

- */ - boolean ShellExecuteEx(ShellAPI.SHELLEXECUTEINFO lpExecInfo); + /** + * Empties the Recycle Bin on the specified drive. + * + * @param hwnd + * A handle to the parent window of any dialog boxes that might + * be displayed during the operation.
+ * This parameter can be NULL. + * @param pszRootPath + * a null-terminated string of maximum length MAX_PATH that + * contains the path of the root
+ * drive on which the Recycle Bin is located. This parameter can + * contain a string formatted with the drive,
+ * folder, and subfolder names, for example c:\windows\system\, + * etc. It can also contain an empty string or
+ * NULL. If this value is an empty string or NULL, all Recycle + * Bins on all drives will be emptied. + * @param dwFlags + * a bitwise combination of SHERB_NOCONFIRMATION, + * SHERB_NOPROGRESSUI and SHERB_NOSOUND.
+ * @return Returns S_OK (0) if successful, or a COM-defined error value + * otherwise.
+ */ + int SHEmptyRecycleBin(HANDLE hwnd, String pszRootPath, int dwFlags); + + /** + * @param lpExecInfo + *

+ * Type: SHELLEXECUTEINFO* + *

+ *

+ * A pointer to a + * SHELLEXECUTEINFO + * structure that contains and receives information + * about the application being executed. + *

+ * @return + *

+ * Returns TRUE if successful; otherwise, + * FALSE. Call + * GetLastError + * for extended error information. + *

+ */ + boolean ShellExecuteEx(ShellAPI.SHELLEXECUTEINFO lpExecInfo); + /** + * 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); } + 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..b0cbc1ce2b --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shlwapi.java @@ -0,0 +1,37 @@ +package com.sun.jna.platform.win32; + +/* + * @author L W Ahonen, lwahonen@iki.fi + */ + +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); + + + /** + * 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); +} 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..f76876673d --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/IShellFolderTest.java @@ -0,0 +1,82 @@ +package com.sun.jna.platform.win32.COM; + +/* + * @author L W Ahonen, lwahonen@iki.fi + */ + +import junit.framework.TestCase; + + +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); + 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; + } + + public void setUp() throws Exception { + Ole32.INSTANCE.CoInitialize(null); + int CSIDL_DRIVES = 0x0011; + WinNT.HRESULT hr = Ole32.INSTANCE.CoInitialize(null); + 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 { + 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); + 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()); + } + peidl.Release(); + assertTrue(sawNames); // We should see at least one item with a name + } +} \ No newline at end of file