在 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 中获取。他们都给出了大致相同的接口定义。
但是那个接口定义不起作用:
- 方法顺序错误,因此调用了错误的方法。
- 字符串未正确传递 - 我的猜测是它们被假定为 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 的引用来使用该接口, 它有效.这些属性以某种方式存在但不可见,或者与我自己定义接口时的默认设置不同。
我从 cargo-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;
};
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 中获取。他们都给出了大致相同的接口定义。
但是那个接口定义不起作用:
- 方法顺序错误,因此调用了错误的方法。
- 字符串未正确传递 - 我的猜测是它们被假定为 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 的引用来使用该接口, 它有效.这些属性以某种方式存在但不可见,或者与我自己定义接口时的默认设置不同。
我从 cargo-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;
};