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

问题描述:

VS 2017年定义Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll这个接口:在C#中定义Visual Studio COM接口时,应该使用哪个类/方法/参数属性?

[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 2016 DLL。因此,我将该定义复制粘贴到我的代码中。

我可以从文档或从Visual Studio本身通过F12获得该定义,当我添加对该DLL的引用时,或从JustDecompile。它们都给出了大致相同的界面定义。

但是,接口定义不工作:

  • 的方法是在错误的顺序,所以那些错误的被调用。
  • 字符串没有正确传入 - 我的猜测是它们被认为是Bstrs,但是这些是LPWStrs。
  • 我经常在通话后遇到访问冲突 - 我的猜测是不正确的调用约定。

如果我申请了一堆属性的接口,因此它成为这样的:

[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的引用使用该接口,则可以工作。这些属性在某种程度上存在但不可见,或者与我自己定义接口时的默认属性不同。

我拼凑起了我从货物崇拜复制,检查IDL和盲目试验和错误中使用的属性,因此我并不真正相信它们。 我该怎么做呢?

这只是JustDecompile这里做不好工作。其他工具,如DotPeek,DnSpy和反射(商业)似乎都工作正常。 Visual Studio F12只是有用的,因为它是集成的,但对interop无用。

另一种选择是在可用时使用C/C++/H/IDL文件。该IDL可以在这里<programfiles>Microsoft Visual Studio\2017\<sku>\VSSDK\VisualStudioIntegration\Common\IDL\vsshell150.idl这里产生的.H头文件<programfiles>Microsoft Visual Studio\2017\<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; 

}; 
+0

谢谢,是的,我使用IDL作为我的来源之一。但是,例如,MethodImplOptions.InternalCall与IDL有什么关系? (如果它不在IDL中,但作为STDMETHODCALLTYPE存在于.h中,则同样的问题适用 - 你如何将它与另一个相关联?) – RichieHindle

+0

感谢指向dotPeek的指针 - 它已立即替换了我的工具箱中的JustDecompile!我不知道JustDecompile会悄悄丢弃这样的属性。 – RichieHindle

+0

STDMETHODCALLTYPE是一个基本上在方法上应用'__stdcall'调用约定的Windows C宏。它在平台调用方法的.NET方面是隐含的,所以你不需要添加它。 InternalCall不一样,它与CLR如何实现所有这些有关,但是你可以忘记这个属性。 –

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

+0

但是当我添加引用Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll而不是0.15,我可以。没有看到IVsSolutionEvents7(“无法找到类型或名称空间名称”)。 – RichieHindle

+0

这些事件支持仅在VS 2017中可用的功能! https://docs.microsoft.com/en-us/visualstudio/extensibility/lightweight-solution-load-extension-impact – ErikEJ

+0

“我想在我的扩展中实现该接口,以便我可以响应这些事件,但我想相同的扩展程序集与Visual Studio 2015兼容“ – RichieHindle