首页 > 解决方案 > 从 C#/F# 使用 IColumnManager 获取/设置列

问题描述

我想在详细信息视图中获取和设置可见列。我有一个 shell 扩展(使用 3rd 方库实现),当用户右键单击文件夹背景时,我将一个菜单项添加到上下文菜单中。通过将 IObjectWithSite 添加到我的扩展中,我已经能够获得到 IColumnManager 的接口。

www.pinvoke.net 上没有 IColumnManager 的声明,我在 .NET 中找到的唯一调用它的示例是在 BExplorer 的一个已失效分支中。基于此,我得到了 GetColumnCount() 工作。

let mutable colCount = 0u;
columnManager.GetColumnCount (CM_ENUM_FLAGS.CM_ENUM_VISIBLE, &colCount)

(我在 F# 中工作。但现在我使用 C# 来声明接口和结构)。

看起来我的下一步是通过调用 GetColumns() 来获取一个 PROPERTYKEY 数组。这被定义为

HRESULT ( STDMETHODCALLTYPE *GetColumns )( 
    __RPC__in IColumnManager * This,
    /* [in] */ CM_ENUM_FLAGS dwFlags,
    /* [size_is][out] */ __RPC__out_ecount_full(cColumns) PROPERTYKEY *rgkeyOrder,
    /* [in] */ UINT cColumns);

这是一个用 C++ 做的例子,取自http://blogs3805.rssing.com/chan-16291381/all_p568.html

PROPERTYKEY *columns = new PROPERTYKEY[nColumns];
            hr = pColumnManager->GetColumns(CM_ENUM_VISIBLE, 
                                            columns, 
                                            nColumns);

BExplorer 为 GetColumns 提供了这个:

void GetColumns(CM_ENUM_FLAGS dwFlags, [Out] [MarshalAs(UnmanagedType.LPArray)] PropertyKey[] rgkeyOrder, uint cColumns);

但在我看来,这里需要 SizeParamIndex,因为我正在编组一个数组。所以我也试过

void GetColumns([In] CM_ENUM_FLAGS dwFlags, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] PROPERTYKEY[] columns, [In] uint colCount);

两者都不起作用。当我这样做时

let columns = Array.init (int colCount) (fun i -> PROPERTYKEY())
columnManager.GetColumns (CM_ENUM_FLAGS.CM_ENUM_VISIBLE, columns, colCount)

我得到一个 HResult=0x80004003 的 System.AccessViolationException。

标签: winapif#shell-extensions

解决方案


我的问题是,在处理 IColumnManager 的 C# 接口声明时,我改变了两个函数的顺序。函数的顺序必须与运行时在 vtable 中找到的顺序相匹配。


推荐阅读