VSIX读取CSPROJ配置属性时抛出COMException未实现异常
问题描述
在VS2022的VSIX(Visual Studio扩展)中,尝试读取当前加载解决方案内各C#项目(csproj)的配置属性.Value时遇到异常。执行以下代码:
var configurationManager = project.ConfigurationManager; if (configurationManager == null) return null; var configuration = configurationManager.ActiveConfiguration; if (configuration == null) return null; var properties = configuration.Properties; if (properties == null) return null; foreach (var property in properties.Cast<Property>()) { // 读取property.Name正常,但读取property.Value抛出COMException '未实现' if (property == null) continue; if (property.Name == "StartWorkingDirectory") workingDir = (string)property.Value; if (property.Name == "StartAction") startProject = 0 == (int)property.Value; if (property.Name == "StartProgram") startExtProg = (string)property.Value; if (property.Name == "StartURL") startBrowser = (string)property.Value; // 其他属性读取... }
读取每个property的.Value时都会抛出COMException:“方法或操作未实现”,但读取.Name完全正常。确认所有目标属性都存在,仅无法读取其值。
环境信息
- VSIX项目使用VS2022模板新建,已引用
Microsoft.VisualStudio.SDK和Microsoft.VisualStudio.BuildTools,自动包含DTE*、stdole、VSLangProj*等引用,手动添加相关NuGet包无效果。 - 测试用例为新建的C# 8控制台应用项目,VS2022已更新至2024年3月最新版本。
解决思路建议
- 改用DTE项目属性读取方式:对于C#项目,可通过
VSLangProj.VSProject接口获取属性,或者直接使用project.Properties.Item("<属性名>").Value的方式读取,绕过Configuration.Properties的COM限制。示例代码:if (project is VSLangProj.VSProject vsProject) { var startActionProp = vsProject.Properties.Item("StartAction"); if (startActionProp != null) { startProject = 0 == (int)startActionProp.Value; } // 其他属性同理 } - 检查项目类型兼容性:确认
project对象是否为真正的C#项目对象,可通过project.Kind判断(C#项目的Kind为{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}),避免对非C#项目执行该逻辑。 - 使用MSBuild API直接读取项目文件:如果DTE方式仍有问题,可通过
Microsoft.Build.Evaluation.Project加载csproj文件,直接读取PropertyGroup中的配置属性,示例:
注意需处理不同配置(Debug/Release)的属性值,可指定对应的Configuration和Platform参数。var msbuildProject = new Microsoft.Build.Evaluation.Project(project.FullName); var startWorkingDir = msbuildProject.GetPropertyValue("StartWorkingDirectory"); - 排查VSIX权限与上下文:确保VSIX在正确的UI线程或DTE上下文下执行,部分属性读取需要在主UI线程操作,可使用
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();切换线程后再读取属性。
内容的提问来源于stack exchange,提问作者Chris Bordeman
相关产品推荐
相关产品推荐

