我正在基于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}分配的内存。
答案 0 :(得分:1)
它应该崩溃。不知道是怎么回事,但我可以猜到。 MSDN文档有点笨拙,它没有按照它们在界面中出现的顺序记录方法。从SDK验证ShObjIdl.idl,Set方法是第一个。所以现在你正在调用完全错误的方法:)只需在你的C#声明中交换它们。
您的SetParentAndItem()声明有错误,您必须从第二个参数中删除ref
。