Я реализую объектную модель, основанную на COM-интерфейсах IShellItem/IShellItem2
в C# и в настоящее время работаю над перечислением элементов. Я хочу избежать использования BindToHandler
, так как считается, что он оказывает заметное влияние на производительность, поэтому я хочу использовать интерфейс и его основные механизмы кэширования.Правильный способ реализации интерфейса COM IParentAndItem
В соответствии с MSDN методы интерфейса IParentAndItem
определяются следующим образом:
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
);
Однако следующий перевод на результаты интерфейса C# COM-взаимодействия в 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);
}
Я используя интерфейс для отливки из IShellItem2
, чтобы получить представление IShellFolder
, используя его метод GetParentAndItem
:
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
Правильная декларация IParentAndItem
, как отметил Ханс 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);
}
После реализации IParentAndItem
и замена BindToHandler
с GetParentAndItem
все, что я могу сказать, что это действительно стоит идти по этому пути эффективность.
Обязательно освободите память, выделенную в GetParentAndItem
для двух PIDL, позвонив по номеру Marshal.FreeCoTaskMem
после того, как вы закончите с этим.
Вы правы, только что отметили, и сначала объявлен SetParentAndItem. Не уверен, откуда взялся этот рефлектор, поскольку он четко обозначен как «Параметр» - спасибо, что указали это. Я также пропустил освобождение памяти, выделенной для 2 PIDL. – atomicode