Task 766: .VBPROJ File Format

Task 766: .VBPROJ File Format

The .VBPROJ file format is an XML-based structure used by Microsoft Visual Studio for Visual Basic .NET projects. It defines project configurations, build settings, references, and included files through a schema aligned with MSBuild, as documented by Microsoft. The format adheres to the namespace http://schemas.microsoft.com/developer/msbuild/2003 and includes elements such as Project, PropertyGroup, ItemGroup, and Import. Detailed specifications can be referenced in the MSBuild project file schema documentation.

  1. The properties intrinsic to the .VBPROJ file format are the MSBuild properties defined within PropertyGroup elements in the XML structure. These properties govern project behavior, compilation, and deployment. Below is a comprehensive list extracted from official MSBuild documentation, including common properties applicable to .VBPROJ files and those specific to Visual Basic projects. Properties are presented in a table for clarity, with descriptions and default values where specified.
Property Name Description Default Value (if specified)
AdditionalLibPaths Specifies additional folders for reference assemblies.
AddModules Makes type information from specified files available to the project.
ALToolPath Path to AL.exe; overrides default version.
ApplicationIcon .ico file embedded as Win32 icon.
ApplicationManifest Path to file for UAC manifest (Windows Vista+).
AssemblyOriginatorKeyFile File (.snk or .pfx) used to sign the assembly.
AssemblySearchPaths List of locations for reference assembly resolution.
AssemblyName Name of the output assembly.
BaseAddress Base address of the output assembly.
BaseIntermediateOutputPath Top-level folder for intermediate output (e.g., obj). obj\
BaseOutputPath Base path for output.
BuildInParallel Enables parallel build of project references. true
BuildProjectReferences Whether to build project references.
CleanFile File used as clean cache.
CodePage Code page for source files.
CompilerResponseFile Response file for compiler tasks.
Configuration Build configuration (e.g., Debug, Release).
CscToolPath Path to csc.exe (C# compiler).
CustomAfterMicrosoftCommonTargets File imported after common targets.
CustomBeforeMicrosoftCommonTargets File imported before common targets.
DebugSymbols Generate debug symbols (.pdb).
DebugType Level of debug info (full, pdbonly, portable, embedded, none).
DefineConstants Conditional compiler constants (semicolon-separated).
DefineDebug Defines DEBUG constant.
DefineTrace Defines TRACE constant.
DelaySign Delay-sign assembly instead of full-signing.
Deterministic Produce identical assemblies for identical inputs.
DirectoryBuildPropsPath Path to override default Directory.Build.props search.
DirectoryBuildTargetsPath Path to override default Directory.Build.targets search.
DisableFastUpToDateCheck Bypass Visual Studio’s fast up-to-date check.
DocumentationFile Name of generated XML doc file.
ErrorReport Compiler error reporting (prompt, send, none).
ExcludeDeploymentUrl Prevents deploymentProvider tag in deployment manifest.
FileAlignment Section alignment in output file (bytes).
FrameworkPathOverride Location of mscorlib.dll and microsoft.visualbasic.dll (VB-specific).
GenerateDocumentationFile Generate XML documentation file.
GenerateFullPaths Generate full paths for filenames in output.
GenerateResourceUsePreserializedResources Use preserialized resources in .resx files.
GenerateSerializationAssemblies Generate XML serialization assemblies (on, auto, off).
ImportDirectoryBuildProps Import Directory.Build.props file.
ImportDirectoryBuildTargets Import Directory.Build.targets file.
IntermediateOutputPath Full path for intermediate output. e.g., obj\debug\
KeyContainerName Strong-name key container name.
KeyOriginatorFile Strong-name key file name.
ModuleAssemblyName Assembly to incorporate compiled module into.
MSBuildProjectExtensionsPath Path for project extensions.
MSBuildTreatWarningsAsErrors Treat all warnings as errors.
MSBuildWarningsAsErrors List of warning codes to treat as errors.
MSBuildWarningsAsMessages List of warning codes to suppress.
NoLogo Suppress compiler logo.
NoStdLib Avoid referencing standard library (mscorlib.dll). false
NoVBRuntimeReference Exclude Visual Basic runtime (Microsoft.VisualBasic.dll) reference (VB-specific).
NoWarn Suppress specific warning numbers.
NoWin32Manifest Do not embed UAC manifest. false
Optimize Enable compiler optimizations.
OptionCompare String comparison: binary or text (VB-specific).
OptionExplicit Require explicit variable declaration (VB-specific).
OptionInfer Enable type inference (VB-specific).
OptionStrict Enforce strict type semantics (VB-specific).
OutDir Final output location for project/solution.
OutputPath Output directory (e.g., bin\Debug).
OutputType Output file format (Library, Exe, Module, Winexe). Library
OverwriteReadOnlyFiles Allow overwriting read-only files.
PathMap Map physical paths to source paths.
PdbFile Name of .pdb file.
Platform Target platform (e.g., Any CPU, x86, x64).
ProcessorArchitecture Assembly reference resolution architecture (msil, x86, amd64, ia64).
ProduceOnlyReferenceAssembly Emit only reference assembly.
ProduceReferenceAssembly Produce reference assemblies.
RegisterAssemblyMSBuildArchitecture Architecture for COM registration (x86, x64, ARM64).
RegisterForCOMInterop Expose COM object via callable wrapper.
RemoveIntegerChecks Disable integer overflow checks (VB-specific). false
RootNamespace Root namespace for embedded resources.
Satellite_* (various) Properties for satellite assembly generation.
SGenToolPath Path to override SGen.exe.
SGenUseProxyTypes Generate proxy types for serialization. true
SkipInvalidConfigurations Warn (don't fail) on invalid platform/configuration combos. false
StartupObject Class/module with Main method.
SubsystemVersion Minimum subsystem version for executable.
TargetCompactFramework .NET Compact Framework version required.
TargetFrameworkVersion .NET Framework version required.
TreatWarningsAsErrors Treat all warnings as errors.
UseCommonOutputDirectory Use same output directory for all solution projects.
UseHostCompilerIfAvailable Use in-process compiler (Visual Studio only).
Utf8Output Log compiler output in UTF-8.
VbcToolPath Path to override vbc.exe (VB-specific).
VbcVerbosity Compiler output verbosity (Quiet, Normal, Verbose) (VB-specific). Normal
VisualStudioVersion Visual Studio version. e.g., 17.0 for VS 2022
WarningsAsErrors Warnings to treat as errors.
WarningLevel Warning level for compiler warnings.
WarningsNotAsErrors Warnings not to treat as errors.
Win32Manifest Manifest file to embed in assembly.
Win32Resource Win32 resource file to embed.

Two direct download links for .VBPROJ files are as follows:

Below is an HTML page with embedded JavaScript that can be hosted on a platform like Ghost (a blogging framework) or any static site. It provides a drag-and-drop area for a .VBPROJ file, parses the XML, extracts values for the properties listed in part 1, and displays them on the screen.

VBPROJ Property Dumper
Drag and drop a .VBPROJ file here

    

  1. Below is a Python class for handling .VBPROJ files. It uses the built-in xml.etree.ElementTree module to parse (decode/read), extract and print property values from the list in part 1, and write modifications back to a file.
import xml.etree.ElementTree as ET

class VBProjHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.tree = None
        self.root = None
        self.properties = [
            'AdditionalLibPaths', 'AddModules', 'ALToolPath', 'ApplicationIcon', 'ApplicationManifest',
            'AssemblyOriginatorKeyFile', 'AssemblySearchPaths', 'AssemblyName', 'BaseAddress',
            'BaseIntermediateOutputPath', 'BaseOutputPath', 'BuildInParallel', 'BuildProjectReferences',
            'CleanFile', 'CodePage', 'CompilerResponseFile', 'Configuration', 'CscToolPath',
            'CustomAfterMicrosoftCommonTargets', 'CustomBeforeMicrosoftCommonTargets', 'DebugSymbols',
            'DebugType', 'DefineConstants', 'DefineDebug', 'DefineTrace', 'DelaySign', 'Deterministic',
            'DirectoryBuildPropsPath', 'DirectoryBuildTargetsPath', 'DisableFastUpToDateCheck',
            'DocumentationFile', 'ErrorReport', 'ExcludeDeploymentUrl', 'FileAlignment',
            'FrameworkPathOverride', 'GenerateDocumentationFile', 'GenerateFullPaths',
            'GenerateResourceUsePreserializedResources', 'GenerateSerializationAssemblies',
            'ImportDirectoryBuildProps', 'ImportDirectoryBuildTargets', 'IntermediateOutputPath',
            'KeyContainerName', 'KeyOriginatorFile', 'ModuleAssemblyName', 'MSBuildProjectExtensionsPath',
            'MSBuildTreatWarningsAsErrors', 'MSBuildWarningsAsErrors', 'MSBuildWarningsAsMessages',
            'NoLogo', 'NoStdLib', 'NoVBRuntimeReference', 'NoWarn', 'NoWin32Manifest', 'Optimize',
            'OptionCompare', 'OptionExplicit', 'OptionInfer', 'OptionStrict', 'OutDir', 'OutputPath',
            'OutputType', 'OverwriteReadOnlyFiles', 'PathMap', 'PdbFile', 'Platform',
            'ProcessorArchitecture', 'ProduceOnlyReferenceAssembly', 'ProduceReferenceAssembly',
            'RegisterAssemblyMSBuildArchitecture', 'RegisterForCOMInterop', 'RemoveIntegerChecks',
            'RootNamespace', 'SGenToolPath', 'SGenUseProxyTypes', 'SkipInvalidConfigurations',
            'StartupObject', 'SubsystemVersion', 'TargetCompactFramework', 'TargetFrameworkVersion',
            'TreatWarningsAsErrors', 'UseCommonOutputDirectory', 'UseHostCompilerIfAvailable',
            'Utf8Output', 'VbcToolPath', 'VbcVerbosity', 'VisualStudioVersion', 'WarningsAsErrors',
            'WarningLevel', 'WarningsNotAsErrors', 'Win32Manifest', 'Win32Resource'
        ]

    def read(self):
        self.tree = ET.parse(self.filepath)
        self.root = self.tree.getroot()

    def print_properties(self):
        if not self.root:
            print("File not read. Call read() first.")
            return
        for prop in self.properties:
            for elem in self.root.iter(prop):
                print(f"{prop}: {elem.text.strip() if elem.text else 'Not set'}")

    def set_property(self, prop_name, value):
        if prop_name not in self.properties:
            print(f"Property {prop_name} not in allowed list.")
            return
        if not self.root:
            print("File not read. Call read() first.")
            return
        # Find or create the property in the first PropertyGroup
        property_groups = self.root.findall(".//{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup")
        if property_groups:
            group = property_groups[0]
            elem = group.find(f"./{prop_name}")
            if elem is None:
                elem = ET.SubElement(group, prop_name)
            elem.text = value

    def write(self, output_path=None):
        if not self.tree:
            print("No data to write. Call read() first.")
            return
        path = output_path or self.filepath
        self.tree.write(path, encoding='utf-8', xml_declaration=True)

# Example usage:
# handler = VBProjHandler('example.vbproj')
# handler.read()
# handler.print_properties()
# handler.set_property('AssemblyName', 'NewAssembly')
# handler.write()
  1. Below is a Java class for handling .VBPROJ files. It uses javax.xml.parsers to parse (decode/read), extract and print property values from the list in part 1, and write modifications back to a file.
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.File;
import java.util.Arrays;
import java.util.List;

public class VBProjHandler {
    private String filepath;
    private Document doc;
    private List<String> properties = Arrays.asList(
        "AdditionalLibPaths", "AddModules", "ALToolPath", "ApplicationIcon", "ApplicationManifest",
        "AssemblyOriginatorKeyFile", "AssemblySearchPaths", "AssemblyName", "BaseAddress",
        "BaseIntermediateOutputPath", "BaseOutputPath", "BuildInParallel", "BuildProjectReferences",
        "CleanFile", "CodePage", "CompilerResponseFile", "Configuration", "CscToolPath",
        "CustomAfterMicrosoftCommonTargets", "CustomBeforeMicrosoftCommonTargets", "DebugSymbols",
        "DebugType", "DefineConstants", "DefineDebug", "DefineTrace", "DelaySign", "Deterministic",
        "DirectoryBuildPropsPath", "DirectoryBuildTargetsPath", "DisableFastUpToDateCheck",
        "DocumentationFile", "ErrorReport", "ExcludeDeploymentUrl", "FileAlignment",
        "FrameworkPathOverride", "GenerateDocumentationFile", "GenerateFullPaths",
        "GenerateResourceUsePreserializedResources", "GenerateSerializationAssemblies",
        "ImportDirectoryBuildProps", "ImportDirectoryBuildTargets", "IntermediateOutputPath",
        "KeyContainerName", "KeyOriginatorFile", "ModuleAssemblyName", "MSBuildProjectExtensionsPath",
        "MSBuildTreatWarningsAsErrors", "MSBuildWarningsAsErrors", "MSBuildWarningsAsMessages",
        "NoLogo", "NoStdLib", "NoVBRuntimeReference", "NoWarn", "NoWin32Manifest", "Optimize",
        "OptionCompare", "OptionExplicit", "OptionInfer", "OptionStrict", "OutDir", "OutputPath",
        "OutputType", "OverwriteReadOnlyFiles", "PathMap", "PdbFile", "Platform",
        "ProcessorArchitecture", "ProduceOnlyReferenceAssembly", "ProduceReferenceAssembly",
        "RegisterAssemblyMSBuildArchitecture", "RegisterForCOMInterop", "RemoveIntegerChecks",
        "RootNamespace", "SGenToolPath", "SGenUseProxyTypes", "SkipInvalidConfigurations",
        "StartupObject", "SubsystemVersion", "TargetCompactFramework", "TargetFrameworkVersion",
        "TreatWarningsAsErrors", "UseCommonOutputDirectory", "UseHostCompilerIfAvailable",
        "Utf8Output", "VbcToolPath", "VbcVerbosity", "VisualStudioVersion", "WarningsAsErrors",
        "WarningLevel", "WarningsNotAsErrors", "Win32Manifest", "Win32Resource"
    );

    public VBProjHandler(String filepath) {
        this.filepath = filepath;
    }

    public void read() throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        doc = builder.parse(new File(filepath));
    }

    public void printProperties() {
        if (doc == null) {
            System.out.println("File not read. Call read() first.");
            return;
        }
        for (String prop : properties) {
            NodeList nodes = doc.getElementsByTagName(prop);
            for (int i = 0; i < nodes.getLength(); i++) {
                String value = nodes.item(i).getTextContent().trim();
                System.out.println(prop + ": " + (value.isEmpty() ? "Not set" : value));
            }
        }
    }

    public void setProperty(String propName, String value) throws Exception {
        if (!properties.contains(propName)) {
            System.out.println("Property " + propName + " not in allowed list.");
            return;
        }
        if (doc == null) {
            System.out.println("File not read. Call read() first.");
            return;
        }
        NodeList groups = doc.getElementsByTagNameNS("http://schemas.microsoft.com/developer/msbuild/2003", "PropertyGroup");
        if (groups.getLength() > 0) {
            Element group = (Element) groups.item(0);
            NodeList elems = group.getElementsByTagName(propName);
            Element elem;
            if (elems.getLength() == 0) {
                elem = doc.createElement(propName);
                group.appendChild(elem);
            } else {
                elem = (Element) elems.item(0);
            }
            elem.setTextContent(value);
        }
    }

    public void write(String outputPath) throws Exception {
        if (doc == null) {
            System.out.println("No data to write. Call read() first.");
            return;
        }
        String path = (outputPath != null) ? outputPath : filepath;
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult result = new StreamResult(new File(path));
        transformer.transform(source, result);
    }

    // Example usage:
    // public static void main(String[] args) throws Exception {
    //     VBProjHandler handler = new VBProjHandler("example.vbproj");
    //     handler.read();
    //     handler.printProperties();
    //     handler.setProperty("AssemblyName", "NewAssembly");
    //     handler.write(null);
    // }
}
  1. Below is a JavaScript class (for Node.js environment) for handling .VBPROJ files. It uses the fs module for file I/O and xml2js (assume installed via npm) to parse (decode/read), extract and print property values from the list in part 1, and write modifications back to a file.
const fs = require('fs');
const xml2js = require('xml2js');

class VBProjHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.data = null;
        this.properties = [
            'AdditionalLibPaths', 'AddModules', 'ALToolPath', 'ApplicationIcon', 'ApplicationManifest',
            'AssemblyOriginatorKeyFile', 'AssemblySearchPaths', 'AssemblyName', 'BaseAddress',
            'BaseIntermediateOutputPath', 'BaseOutputPath', 'BuildInParallel', 'BuildProjectReferences',
            'CleanFile', 'CodePage', 'CompilerResponseFile', 'Configuration', 'CscToolPath',
            'CustomAfterMicrosoftCommonTargets', 'CustomBeforeMicrosoftCommonTargets', 'DebugSymbols',
            'DebugType', 'DefineConstants', 'DefineDebug', 'DefineTrace', 'DelaySign', 'Deterministic',
            'DirectoryBuildPropsPath', 'DirectoryBuildTargetsPath', 'DisableFastUpToDateCheck',
            'DocumentationFile', 'ErrorReport', 'ExcludeDeploymentUrl', 'FileAlignment',
            'FrameworkPathOverride', 'GenerateDocumentationFile', 'GenerateFullPaths',
            'GenerateResourceUsePreserializedResources', 'GenerateSerializationAssemblies',
            'ImportDirectoryBuildProps', 'ImportDirectoryBuildTargets', 'IntermediateOutputPath',
            'KeyContainerName', 'KeyOriginatorFile', 'ModuleAssemblyName', 'MSBuildProjectExtensionsPath',
            'MSBuildTreatWarningsAsErrors', 'MSBuildWarningsAsErrors', 'MSBuildWarningsAsMessages',
            'NoLogo', 'NoStdLib', 'NoVBRuntimeReference', 'NoWarn', 'NoWin32Manifest', 'Optimize',
            'OptionCompare', 'OptionExplicit', 'OptionInfer', 'OptionStrict', 'OutDir', 'OutputPath',
            'OutputType', 'OverwriteReadOnlyFiles', 'PathMap', 'PdbFile', 'Platform',
            'ProcessorArchitecture', 'ProduceOnlyReferenceAssembly', 'ProduceReferenceAssembly',
            'RegisterAssemblyMSBuildArchitecture', 'RegisterForCOMInterop', 'RemoveIntegerChecks',
            'RootNamespace', 'SGenToolPath', 'SGenUseProxyTypes', 'SkipInvalidConfigurations',
            'StartupObject', 'SubsystemVersion', 'TargetCompactFramework', 'TargetFrameworkVersion',
            'TreatWarningsAsErrors', 'UseCommonOutputDirectory', 'UseHostCompilerIfAvailable',
            'Utf8Output', 'VbcToolPath', 'VbcVerbosity', 'VisualStudioVersion', 'WarningsAsErrors',
            'WarningLevel', 'WarningsNotAsErrors', 'Win32Manifest', 'Win32Resource'
        ];
    }

    async read() {
        const xml = fs.readFileSync(this.filepath, 'utf8');
        const parser = new xml2js.Parser({ explicitArray: false });
        this.data = await parser.parseStringPromise(xml);
    }

    printProperties() {
        if (!this.data) {
            console.log('File not read. Call read() first.');
            return;
        }
        const propertyGroups = this.data.Project.PropertyGroup;
        if (Array.isArray(propertyGroups)) {
            propertyGroups.forEach(group => this._extractFromGroup(group));
        } else if (propertyGroups) {
            this._extractFromGroup(propertyGroups);
        }
    }

    _extractFromGroup(group) {
        this.properties.forEach(prop => {
            if (group[prop]) {
                console.log(`${prop}: ${group[prop] || 'Not set'}`);
            }
        });
    }

    setProperty(propName, value) {
        if (!this.properties.includes(propName)) {
            console.log(`Property ${propName} not in allowed list.`);
            return;
        }
        if (!this.data) {
            console.log('File not read. Call read() first.');
            return;
        }
        let propertyGroups = this.data.Project.PropertyGroup;
        if (!Array.isArray(propertyGroups)) {
            propertyGroups = [propertyGroups];
        }
        const group = propertyGroups[0];
        group[propName] = value;
    }

    write(outputPath = null) {
        if (!this.data) {
            console.log('No data to write. Call read() first.');
            return;
        }
        const builder = new xml2js.Builder({ renderOpts: { pretty: true, indent: '  ', newline: '\n' }, xmldec: { version: '1.0', encoding: 'utf-8' } });
        const xml = builder.buildObject(this.data);
        const path = outputPath || this.filepath;
        fs.writeFileSync(path, xml);
    }
}

// Example usage:
// const handler = new VBProjHandler('example.vbproj');
// await handler.read();
// handler.printProperties();
// handler.setProperty('AssemblyName', 'NewAssembly');
// handler.write();
  1. Below is a C++ class for handling .VBPROJ files. Note that C++ does not have a built-in XML parser, so this implementation assumes the use of an external library like TinyXML-2 (include via #include <tinyxml2.h>). It parses (decode/read), extracts and prints property values from the list in part 1, and writes modifications back to a file. If TinyXML-2 is not available, a custom parser would be required, but this provides a functional example.
#include <iostream>
#include <string>
#include <vector>
#include <tinyxml2.h>  // Assume TinyXML-2 library is included

class VBProjHandler {
private:
    std::string filepath;
    tinyxml2::XMLDocument doc;
    std::vector<std::string> properties = {
        "AdditionalLibPaths", "AddModules", "ALToolPath", "ApplicationIcon", "ApplicationManifest",
        "AssemblyOriginatorKeyFile", "AssemblySearchPaths", "AssemblyName", "BaseAddress",
        "BaseIntermediateOutputPath", "BaseOutputPath", "BuildInParallel", "BuildProjectReferences",
        "CleanFile", "CodePage", "CompilerResponseFile", "Configuration", "CscToolPath",
        "CustomAfterMicrosoftCommonTargets", "CustomBeforeMicrosoftCommonTargets", "DebugSymbols",
        "DebugType", "DefineConstants", "DefineDebug", "DefineTrace", "DelaySign", "Deterministic",
        "DirectoryBuildPropsPath", "DirectoryBuildTargetsPath", "DisableFastUpToDateCheck",
        "DocumentationFile", "ErrorReport", "ExcludeDeploymentUrl", "FileAlignment",
        "FrameworkPathOverride", "GenerateDocumentationFile", "GenerateFullPaths",
        "GenerateResourceUsePreserializedResources", "GenerateSerializationAssemblies",
        "ImportDirectoryBuildProps", "ImportDirectoryBuildTargets", "IntermediateOutputPath",
        "KeyContainerName", "KeyOriginatorFile", "ModuleAssemblyName", "MSBuildProjectExtensionsPath",
        "MSBuildTreatWarningsAsErrors", "MSBuildWarningsAsErrors", "MSBuildWarningsAsMessages",
        "NoLogo", "NoStdLib", "NoVBRuntimeReference", "NoWarn", "NoWin32Manifest", "Optimize",
        "OptionCompare", "OptionExplicit", "OptionInfer", "OptionStrict", "OutDir", "OutputPath",
        "OutputType", "OverwriteReadOnlyFiles", "PathMap", "PdbFile", "Platform",
        "ProcessorArchitecture", "ProduceOnlyReferenceAssembly", "ProduceReferenceAssembly",
        "RegisterAssemblyMSBuildArchitecture", "RegisterForCOMInterop", "RemoveIntegerChecks",
        "RootNamespace", "SGenToolPath", "SGenUseProxyTypes", "SkipInvalidConfigurations",
        "StartupObject", "SubsystemVersion", "TargetCompactFramework", "TargetFrameworkVersion",
        "TreatWarningsAsErrors", "UseCommonOutputDirectory", "UseHostCompilerIfAvailable",
        "Utf8Output", "VbcToolPath", "VbcVerbosity", "VisualStudioVersion", "WarningsAsErrors",
        "WarningLevel", "WarningsNotAsErrors", "Win32Manifest", "Win32Resource"
    };

public:
    VBProjHandler(const std::string& filepath) : filepath(filepath) {}

    bool read() {
        return doc.LoadFile(filepath.c_str()) == tinyxml2::XML_SUCCESS;
    }

    void printProperties() {
        if (doc.Error()) {
            std::cout << "File not read. Call read() first." << std::endl;
            return;
        }
        tinyxml2::XMLElement* root = doc.FirstChildElement("Project");
        if (!root) return;
        for (const std::string& prop : properties) {
            tinyxml2::XMLElement* elem = root->FirstChildElement(prop.c_str());
            while (elem) {
                const char* text = elem->GetText();
                std::cout << prop << ": " << (text ? text : "Not set") << std::endl;
                elem = elem->NextSiblingElement(prop.c_str());
            }
        }
    }

    void setProperty(const std::string& propName, const std::string& value) {
        auto it = std::find(properties.begin(), properties.end(), propName);
        if (it == properties.end()) {
            std::cout << "Property " << propName << " not in allowed list." << std::endl;
            return;
        }
        if (doc.Error()) {
            std::cout << "File not read. Call read() first." << std::endl;
            return;
        }
        tinyxml2::XMLElement* root = doc.FirstChildElement("Project");
        if (!root) return;
        tinyxml2::XMLElement* group = root->FirstChildElement("PropertyGroup");
        if (!group) {
            group = doc.NewElement("PropertyGroup");
            root->InsertEndChild(group);
        }
        tinyxml2::XMLElement* elem = group->FirstChildElement(propName.c_str());
        if (!elem) {
            elem = doc.NewElement(propName.c_str());
            group->InsertEndChild(elem);
        }
        elem->SetText(value.c_str());
    }

    bool write(const std::string& outputPath = "") {
        if (doc.Error()) {
            std::cout << "No data to write. Call read() first." << std::endl;
            return false;
        }
        std::string path = outputPath.empty() ? filepath : outputPath;
        return doc.SaveFile(path.c_str()) == tinyxml2::XML_SUCCESS;
    }
};

// Example usage:
// int main() {
//     VBProjHandler handler("example.vbproj");
//     if (handler.read()) {
//         handler.printProperties();
//         handler.setProperty("AssemblyName", "NewAssembly");
//         handler.write();
//     }
//     return 0;
// }