VS2022扩展升级:IVsSolution转IVsSolution4失败求助
问题描述
将适配Visual Studio 2017的扩展升级至Visual Studio 2022时,原有的ReloadProject辅助方法在转换IVsSolution到IVsSolution4时抛出InvalidCastException,异常信息显示无法将Microsoft.VisualStudio.CommonIDE.Solutions.Solution类型转换为Microsoft.VisualStudio.Shell.Interop.IVsSolution4。该方法在VS2017中可正常工作,且测试发现返回对象可转换为IVsSolution、IVsSolution2和IVsSolution3。
原方法代码如下:
static internal EnvDTE.Project ReloadProject(EnvDTE.Project proj, Action duringUnload = null) { Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread(); IVsSolution sol = (IVsSolution)ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)); IVsHierarchy selectedHierarchy; ErrorHandler.ThrowOnFailure(sol.GetProjectOfUniqueName(proj.UniqueName, out selectedHierarchy)); Guid guid; sol.GetGuidOfProject(selectedHierarchy, out guid); sol.CloseSolutionElement((uint)__VSSLNCLOSEOPTIONS.SLNCLOSEOPT_UnloadProject, selectedHierarchy, 0); if (duringUnload != null) duringUnload(); IVsSolution4 sol4 = (IVsSolution4)sol; ErrorHandler.ThrowOnFailure(sol4.ReloadProject(guid)); return GetProject(guid); }
异常详情:
System.InvalidCastException HResult=0x80004002 Message=Unable to cast object of type 'Microsoft.VisualStudio.CommonIDE.Solutions.Solution' to type 'Microsoft.VisualStudio.Shell.Interop.IVsSolution4'. Source=<Project Name> StackTrace: at <Project>.Utilities.DTE.ReloadProject(Project proj, Action duringUnload) in <FilePath>\Utilities\DTE.cs:line 185 at <Project>.Features.NuGetBackedFeature.Enable(Project project) in <FilePath>\Features\NuGetBackedFeature.cs:line 41 at <Project>.MyPackage.<>c.<InitializeAsync>b__1_6(Object sender, EventArgs e) in <FilePath>\MyPackage.cs:line 105 at Microsoft.VisualStudio.Shell.OleMenuCommand.Invoke(Object inArg, IntPtr outArg, OLECMDEXECOPT options) at Microsoft.VisualStudio.Shell.OleMenuCommandService.Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget.Exec(Guid& commandGroup, UInt32 nCmdId, UInt32 nCmdExcept, IntPtr pIn, IntPtr vOut)
解决方案
方法1:用QueryInterface显式获取IVsSolution4实例
直接强制转换失败时,改用COM互操作的QueryInterface方式获取接口:
IVsSolution4 sol4 = null; if (sol is IUnknown unknown) { Guid ivsSolution4Guid = typeof(IVsSolution4).GUID; IntPtr ptr = IntPtr.Zero; int hr = unknown.QueryInterface(ref ivsSolution4Guid, out ptr); if (ErrorHandler.Succeeded(hr) && ptr != IntPtr.Zero) { sol4 = Marshal.GetObjectForIUnknown(ptr) as IVsSolution4; Marshal.Release(ptr); } } if (sol4 != null) { ErrorHandler.ThrowOnFailure(sol4.ReloadProject(guid)); } else { // 降级处理逻辑,比如使用IVsSolution3的替代方案 }
方法2:改用DTE高层API实现重载
直接利用EnvDTE.Project自带的Unload和Reload方法,无需依赖IVsSolution系列接口,兼容性更强:
static internal EnvDTE.Project ReloadProject(EnvDTE.Project proj, Action duringUnload = null) { Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread(); proj.Unload(); duringUnload?.Invoke(); proj.Reload(); return proj; }
该方式在VS2017和VS2022中均能稳定运行,代码更简洁。
方法3:检查VS SDK引用版本
确保扩展项目引用了Visual Studio 2022对应的SDK包,版本不低于17.0.x。在NuGet包管理器中确认Microsoft.VisualStudio.Shell.17.0或更高版本已安装,避免因SDK版本不匹配导致接口定义不一致。
内容的提问来源于stack exchange,提问作者Ganon11
相关产品推荐
相关产品推荐

