我正在基于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进行IShellItem2转换的接口,以使用其GetParentAndItem方法获取IShellFolder表示形式:

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

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并用GetParentAndItem替换BindToHandler ,我可以说确实值得在此路由性能方面保持明智。

完成这些操作后,请确保通过调用Marshal.FreeCoTaskMem释放在GetParentAndItem为两个PIDL分配的内存。

#1楼 票数:1 已采纳

它应该崩溃了。 不知道怎么回事,但我可以猜测。 MSDN文档有点笨拙,它没有按照方法在界面中出现的顺序来记录方法。 使用SDK中的ShObjIdl.idl进行验证,首先使用Set方法。 因此,现在您正在调用完全错误的方法:)只需在C#声明中交换它们即可。

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

  ask by atomicode translate from so

未解决问题?本站智能推荐:

2回复

可以在C#中实现此COM接口吗?

COM 组件目前是用 C++ 实现的,下一个版本必须用 C# 实现。 该组件是从 C++(不是 CLI)代码调用的。 不是那么小的组件的主要部分已经移植到 C#,但我很难弄清楚如何翻译一种特定的方法。 接口定义 IDL 中使用了以下导入: 接口的主要部分已经转换为相应的 C# 属性、接口和类。 它
4回复

如何调用在基类中定义的专用COM接口的方法?

如何从派生类调用在基类中定义的私有COM接口的方法? 例如,这是COM接口IComInterface (IDL): 这是OldLibrary程序集的C#类BaseClass ,它像这样实现IComInterface (请注意,接口被声明为private): 最后,这是一个改进的版本I
3回复

在.NET中调用COM枚举器的正确方法是什么?

我正在调用一个外部提供的COM DLL,我已经生成了一个COM互操作包装器。 为了参数,让我们调用我想调用IEnumFoo的接口。 IEnumFoo具有典型的COM枚举器模式: HRESULT Next ( ULONG celt, IFoo** rgel
2回复

WebBrowserSite:如何在派生类中调用私有COM接口方法?

这是挑战。 我是从Framework的WebBrowserSite类派生出来的。 我的派生类ImprovedWebBrowserSite一个实例是通过WebBrowser.CreateWebBrowserSiteBase返回的,我在WebBrowser类的派生版本中覆盖了它 - 专门用于提供
1回复

COM方法,Char类型和CharSet

这是我先前的问题的后续内容: .NET互操作是来回复制数组数据,还是将数组固定? 我的方法是COM接口方法(而不是DllImport方法)。 C#签名如下所示: MSDN 说 : 将默认情况下具有Unicode格式的托管Char类型传递给非托管代码时,互操作封送处理程序会将字符集
2回复

如何恢复尚未正确释放的COM对象?

当有人使用任务管理器结束已实例化COM对象的.NET进程时,AFAIK无法using {}或事件处理块在try {} finally {}调用Marshal.FinalReleaseComObject 。 下次启动应用程序时,COM对象处于不可用状态,我需要重新启动计算机以使其再次运行。
1回复

MethodImplAttribute(InternalCall,Runtime)对COMInterop接口的方法做了什么?

在Windows API Code Pack for .NET Framework中 ,COM Interop接口的许多方法都使用MethodImplAttribute进行修饰,例如: MethodImplOptions.InternalCall值的文档说: 调用是内部的,也就是说,它
1回复

实例化.Net中具有VB6定义的COM接口的.Net对象,将引发TypeLoadException

我在名为IODevice的VB6 COM DLL中定义了一个COM接口。 我有一个.Net类,可以导入和实现此接口。 该对象运行良好,可以在VB6中使用CreateObject()创建并作为IODevice接口引用。 我现在将调用代码移至.Net并使用Activator.Create