Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IShellFolder support #524

Merged
merged 12 commits into from
Dec 4, 2015
1 change: 1 addition & 0 deletions CHANGES.md
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -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): 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
---------
Expand Down
229 changes: 229 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/COM/IEnumIDList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package com.sun.jna.platform.win32.COM;

/*
* @author L W Ahonen, [email protected]
*/

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}));
}
};
}
}
}
Loading