Skip to content

Commit

Permalink
Merge branch 'lwahonen-IShellFolder_support'
Browse files Browse the repository at this point in the history
  • Loading branch information
twall committed Dec 4, 2015
2 parents e002377 + 8d728c6 commit aa47504
Show file tree
Hide file tree
Showing 7 changed files with 947 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------
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

0 comments on commit aa47504

Please sign in to comment.