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

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 this interface in my extension so that I can respond to these events, but I want the same assembly assembly to be compatible with Visual Studio 2015, so I don't need a dependency on this VS 2017 DLL. Therefore, I will copy this definition into my code.

I can get this definition from the documentation or from Visual Studio itself through F12 when I add a link to this DLL or from JustDecompile. They all give roughly the same definition of an interface.

But this interface definition does not work:

  • The methods are in the wrong order, so the wrong ones are called.
  • Lines are not transmitted properly - I assume they are considered BStrs, but these are LPWStrs.
  • I often get an access violation after a call - my guess is the wrong calling convention.

If I applied a bunch of attributes to the interface, then it becomes the following:

 [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 correct order, then it works.

How should you know which of these attributes to use, or which order to enter the methods? The documentation is not necessarily useful - the documentation for this interface , for example, does not add anything to the simple broken definition above.

Even if I have access to the 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 this DLL in Visual Studio or JustDecompile, I see only this simple definition, and yet, if I use the interface through a link to this DLL, it works. The attributes are somehow there, but invisible, or by default different from when I define the interface myself.

I combined the attributes that I use, from copying with load, studying IDL, and blind tests and errors, and therefore I really do not trust them. How can I do it?

0
source share
2 answers

It is just that JustDecompile does not work well here. Other tools like DotPeek, DnSpy and Reflector (commercial) all work fine. Visual Studio F12 is only useful because it is integrated, but is useless for interaction.

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

This is the law. If in doubt, refer to one of them (I prefer the smallest binary level .h,

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; }; 
+2
source

Just use Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll, all new versions of VS have binding redirects

+1
source

Source: https://habr.com/ru/post/1272078/


All Articles