2015-03-31 5 views
0

Я реализую объектную модель, основанную на 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 после того, как вы закончите с этим.

ответ

1

Предполагается, что он потерпит крах. Не знаю, как это произошло, но я могу догадаться. Документы MSDN немного неуклюжи, они не документируют методы в том порядке, в котором они отображаются в интерфейсе. Проверьте с помощью ShObjIdl.idl из SDK, сначала установите метод Set. Поэтому прямо сейчас вы вызываете совершенно неправильный метод :) Просто поменяйте их на свое объявление C#.

У вашего объявления SetParentAndItem() есть ошибка, вы должны удалить ref из второго аргумента.

+0

Вы правы, только что отметили, и сначала объявлен SetParentAndItem. Не уверен, откуда взялся этот рефлектор, поскольку он четко обозначен как «Параметр» - спасибо, что указали это. Я также пропустил освобождение памяти, выделенной для 2 PIDL. – atomicode

Смежные вопросы