I'm implementing an object model based on the IShellItem/IShellItem2
COM interfaces in C# and am currently working on item enumeration. I want to avoid using BindToHandler
as it is considered to have a notable impact on performance, this is why i want to use the IParentAndItem
interface and its underlying caching mechanisms.
According to MSDN the methods of the IParentAndItem
interface are defined as follows:
HRESULT GetParentAndItem(
[out, optional] PIDLIST_ABSOLUTE *ppidlParent,
[out, optional] IShellFolder **ppsf,
[out, optional] PITEMID_CHILD *ppidlChild
);
HRESULT SetParentAndItem(
[in] PCIDLIST_ABSOLUTE pidlParent,
[in] IShellFolder *psf,
[in] PCUITEMID_CHILD pidlChild
);
However the following translation into a C# COM Interop interface results in an AccessViolationException
:
[ComImport,
Guid("B3A4B685-B685-4805-99D9-5DEAD2873236"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IParentAndItem
{
void GetParentAndItem(out IntPtr ppidlParent, out IShellFolder ppsf, out IntPtr ppidlChild);
void SetParentAndItem(IntPtr pidlParent, ref IShellFolder psf, IntPtr pidlChild);
}
I'm using the interface to cast from an IShellItem2
to get the IShellFolder
representation using its GetParentAndItem
method:
IParentAndItem pni = si as IParentAndItem; // 'si' is the IShellItem2
if(pni != null)
{
IntPtr ppidlParent, ppidlChild;
IShellFolder ppsf;
pni.GetParentAndItem(out ppidlParent, out ppsf, out ppidlChild); // <-- throws AccessViolationException
// Work with ppsf, e.g. EnumObjects
}
UPDATE
The correct declaration of IParentAndItem
as pointed out by Hans Passant:
[ComImport,
Guid("B3A4B685-B685-4805-99D9-5DEAD2873236"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IParentAndItem
{
void SetParentAndItem(IntPtr pidlParent, IShellFolder psf, IntPtr pidlChild);
void GetParentAndItem(out IntPtr ppidlParent, out IShellFolder ppsf, out IntPtr ppidlChild);
}
After implementing IParentAndItem
and replacing BindToHandler
with GetParentAndItem
all i can say it is really worth going this route performance wise.
Be sure to free memory allocated in GetParentAndItem
for the two PIDLs by calling Marshal.FreeCoTaskMem
after you're done with those.
It is supposed to crash. Not sure how it happened but I can guess. The MSDN docs are a bit clumsy, it does not document the methods in the order in which they appear in the interface. Verify with ShObjIdl.idl from the SDK, the Set method is first. So right now you are calling the completely wrong method :) Just swap them in your C# declaration.
Your SetParentAndItem() declaration has a bug, you must remove ref
from the second argument.