实现IParentAndItem COM接口的正确方法

时间:2015-03-31 13:00:04

标签: c# .net com-interop

我正在基于C#中的IShellItem/IShellItem2 COM接口实现一个对象模型,目前正在处理项枚举。我想避免使用BindToHandler,因为它被认为对性能有显着影响,这就是为什么我想使用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 Interop接口会产生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
}

更新

Hans Passant指出的IParentAndItem的正确声明:

[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之后,我可以说明白这条路线的确非常值得。

确保在完成这两个PIDL后,通过调用GetParentAndItem释放Marshal.FreeCoTaskMem中为{2}分配的内存。

1 个答案:

答案 0 :(得分:1)

它应该崩溃。不知道是怎么回事,但我可以猜到。 MSDN文档有点笨拙,它没有按照它们在界面中出现的顺序记录方法。从SDK验证ShObjIdl.idl,Set方法是第一个。所以现在你正在调用完全错误的方法:)只需在你的C#声明中交换它们。

您的SetParentAndItem()声明有错误,您必须从第二个参数中删除ref