在C#中定义Visual Studio COM接口时,应该使用哪些类/方法/参数属性? [英] When defining a Visual Studio COM interface in C#, which class / method / parameter attributes should I use?

查看:176
本文介绍了在C#中定义Visual Studio COM接口时,应该使用哪些类/方法/参数属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

VS 2017在Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll中定义了此接口:

  [Guid(  A459C228-5617-4136-BCBE-C282DF6D9A62)] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
公共接口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。因此,我将该定义复制粘贴到我的代码中。



我可以从文档中获取该定义,也可以通过添加F12从Visual Studio本身获取该定义。 DLL,或来自JustDecompile。它们都给出了大致相同的接口定义。



但是该接口定义不起作用:




  • 方法顺序错误,因此调用错误的方法。

  • 字符串未正确传递-我的

  • 我经常在通话后收到访问冲突-我的猜测是不正确的调用约定。



如果我在接口上应用了一堆属性,它就会变成这样:

  [ComVisible(true)] 
[ComImport]
[Guid( A459C228-5617-4136-BCBE-C282DF6D9A62)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ]
公共接口IVsSolutionEvents7
{
[PreserveSig,MethodImpl(MethodImplOptions.InternalCall,MethodCodeType = MethodCodeType.Runtime)]
int OnAfterOpenFolder([In,MarshalAs(UnmanagedType.LPWStr)]字符串folderPath);
...

并按正确的顺序排列方法,然后就可以使用了。 / p>

您应该如何知道要使用哪些属性,或将这些方法放入哪个顺序?该文档不一定有用-该接口的文档,不会为上面的简单断开定义添加任何内容。



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



我将我从货神崇拜复制中使用的属性拼凑在一起,检查IDL,盲目尝试和错误,因此,我真的不信任他们。 我应该怎么做?

解决方案

只是JustDecompile在这里做得不好。其他工具,例如DotPeek,DnSpy和Reflector(商业)似乎都可以正常工作。 Visual Studio F12仅是有用的,因为它是集成的,但对于互操作却没有用。



另一种选择是在C / C ++ / H / 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:公共IUnknown
{
公共:
虚拟HRESULT STDMETHODCALLTYPE OnAfterOpenFolder(
/ * [in] * / __RPC__in LPCOLESTR folderPath)= 0;

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

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

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

虚拟HRESULT STDMETHODCALLTYPE OnAfterLoadAllDeferredProjects(void)= 0;

};


VS 2017 defines this interface in 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);
}

I want to implement that interface in my extension so that I can respond to those events, but I want the same extension assembly to be compatible with Visual Studio 2015, so I don't want a dependency on that VS 2017 DLL. Therefore, I copy-paste that definition into my code.

I can get that definition from the documentation, or from Visual Studio itself via F12 when I add a reference to that DLL, or from JustDecompile. They all give roughly the same definition of the interface.

But that interface definition doesn't work:

  • The methods are in the wrong order, so the wrong ones get called.
  • The strings aren't passed in properly - my guess is that they are assumed to be BStrs but these are LPWStrs.
  • I often get an access violation after a call - my guess is an incorrect calling convention.

If I apply a pile of attributes to the interface, so it becomes this:

[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);
    ...

and put the methods in the right order, then it works.

How are you supposed to know which of those attributes to use, or which order to to put the methods in? The documentation is not necessarily useful - the documentation for that interface, for example, adds nothing to the simple broken definition above.

Even when I have access to an assembly that defines the interface (Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll in this case), where do these attributes go? When I look at the definition in that DLL in either Visual Studio or JustDecompile, I only see that simple definition, and yet if I use the interface via a reference to that DLL, it works. The attributes are somehow there but invisible, or are being defaulted differently from when I define the interface myself.

I cobbled together the attributes I'm using from cargo-cult copying, examining the IDL, and blind trial and error, and as such I don't really trust them. How should I have done it?

解决方案

It's just that JustDecompile does a bad job here. Other tools such as DotPeek, DnSpy and Reflector (commercial) all seem to work fine. Visual Studio F12 is only useful because it's integrated, but useless for interop.

Another option is to use the C/C++/H/IDL files when they are available. The IDL is available here <programfiles>Microsoft Visual Studio\2017\<sku>\VSSDK\VisualStudioIntegration\Common\IDL\vsshell150.idl and the resulting .h header file here <programfiles>Microsoft Visual Studio\2017\<sku>\VSSDK\VisualStudioIntegration\Common\inc\vsshell150.h

They are the law. When in doubt, refer to one of them (I prefer the .h, the lowest binary level).

This is how IVsSolutionEvents7 is defined in the .h file:

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;

};

这篇关于在C#中定义Visual Studio COM接口时,应该使用哪些类/方法/参数属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆