在 C# 中定义 Visual Studio COM 接口时,我应该使用哪个 class / 方法 / 参数属性?

When defining a Visual Studio COM interface in C#, which class / method / parameter attributes should I use?

VS 2017 在Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll:

中定义了这个接口
[Guid("A459C228-5617-4136-BCBE-C282DF6D9A62")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IVsSolutionEvents7
{
    void OnAfterCloseFolder(string folderPath);
    void OnAfterLoadAllDeferredProjects();
    void OnAfterOpenFolder(string folderPath);
    void OnBeforeCloseFolder(string folderPath);
    void OnQueryCloseFolder(string folderPath, ref int pfCancel);
}

我想在我的扩展中实现该接口,以便我可以响应这些事件,但我希望相同的扩展程序集与 Visual Studio 2015 兼容,所以我不希望依赖于VS 2017 DLL。因此,我将该定义复制粘贴到我的代码中。

我可以从文档中获取该定义,或者当我添加对该 DLL 的引用时通过 F12 从 Visual Studio 本身获取该定义,或者从 JustDecompile 中获取。他们都给出了大致相同的接口定义。

但是那个接口定义不起作用:

如果我把一堆属性应用到接口上,那么就变成了这样:

[ComVisible(true)]
[ComImport]
[Guid("A459C228-5617-4136-BCBE-C282DF6D9A62")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IVsSolutionEvents7
{
    [PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    int OnAfterOpenFolder([In, MarshalAs(UnmanagedType.LPWStr)] string folderPath);
    ...

并按正确的顺序排列方法,然后就可以了。

您怎么知道要使用哪些属性,或者按什么顺序放置这些方法?该文档不一定有用 - 例如,documentation for that interface 没有对上面简单的损坏定义添加任何内容。

即使我可以访问定义接口的程序集(在本例中为 Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll),这些属性去哪儿了?当我在 Visual Studio 或 JustDecompile 中查看该 DLL 中的定义时,我只看到那个简单的定义,但是如果我通过对该 DLL 的引用来使用该接口, 它有效.这些属性以某种方式存在但不可见,或者与我自己定义接口时的默认设置不同。

我从 c​​argo-cult 复制、检查 IDL 和盲目试错中拼凑了我正在使用的属性,因此我并不真正信任它们。 我应该怎么做?

只需使用 Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll,所有较新的 VS 版本都有绑定重定向

只是JustDecompile在这里做的不好。 DotPeek、DnSpy 和 Reflector(商业)等其他工具似乎都可以正常工作。 Visual Studio F12 仅在集成时有用,但对互操作毫无用处。

另一种选择是在 C/C++/H/IDL 文件可用时使用它们。 IDL 可在此处获得 <programfiles>Microsoft Visual Studio17\<sku>\VSSDK\VisualStudioIntegration\Common\IDL\vsshell150.idl,生成的 .h 头文件可在此处获得 <programfiles>Microsoft Visual Studio17\<sku>\VSSDK\VisualStudioIntegration\Common\inc\vsshell150.h

他们是法律。如有疑问,请参考其中之一(我更喜欢 .h,最低二进制级别)。

这是 IVsSolutionEvents7 在 .h 文件中的定义方式:

MIDL_INTERFACE("A459C228-5617-4136-BCBE-C282DF6D9A62")
IVsSolutionEvents7 : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE OnAfterOpenFolder( 
        /* [in] */ __RPC__in LPCOLESTR folderPath) = 0;

    virtual HRESULT STDMETHODCALLTYPE OnBeforeCloseFolder( 
        /* [in] */ __RPC__in LPCOLESTR folderPath) = 0;

    virtual HRESULT STDMETHODCALLTYPE OnQueryCloseFolder( 
        /* [in] */ __RPC__in LPCOLESTR folderPath,
        /* [out][in] */ __RPC__inout BOOL *pfCancel) = 0;

    virtual HRESULT STDMETHODCALLTYPE OnAfterCloseFolder( 
        /* [in] */ __RPC__in LPCOLESTR folderPath) = 0;

    virtual HRESULT STDMETHODCALLTYPE OnAfterLoadAllDeferredProjects( void) = 0;

};