Task 797: .VSTO File Format
Task 797: .VSTO File Format
File Format Specifications for .VSTO
The .VSTO file format is an XML-based deployment manifest used for Visual Studio Tools for Office (VSTO) solutions. It follows the ClickOnce deployment manifest schema, with specific adaptations for Office add-ins and document-level customizations. The file describes the deployment settings, assembly dependencies, and digital signatures to ensure secure installation and update of Office solutions. The structure is hierarchical, with a root element and various child elements and attributes that define the manifest's content.
1. List of All Properties Intrinsic to the File Format
The properties are the XML elements and attributes that define the file's structure. They are intrinsic to the format as they determine how the file is parsed and used by the VSTO runtime. The following is a hierarchical list based on the ClickOnce schema, including descriptions, types, and requirement status:
assembly (Element)
- Description: Required top-level element representing the entire manifest.
- Attributes:
- manifestVersion (type: string, required): Specifies the version of the manifest schema (e.g., "1.0").
- Required: Yes.
assemblyIdentity (Element, child of assembly or dependentAssembly)
- Description: Identifies the manifest or dependent assembly.
- Attributes:
- name (type: string, required): Name of the assembly (e.g., "ContosoOfficeSolutions.vsto").
- version (type: string, required): Version number (e.g., "1.0.0.0").
- publicKeyToken (type: string, optional): Public key token for strong naming.
- processorArchitecture (type: string, optional): Processor architecture (e.g., "msil").
- culture (type: string, optional): Culture or language (e.g., "neutral").
- type (type: string, optional): Assembly type (e.g., "win32" for dependent assemblies).
- Required: Yes.
description (Element, child of assembly)
- Description: Provides metadata about the application for shell presence and control panel display.
- Attributes:
- publisher (type: string, optional): Publisher name (e.g., "Microsoft").
- product (type: string, optional): Product name (e.g., "ContosoOfficeSolutions").
- supportUrl (type: string, optional): URL for support information.
- Required: Yes.
deployment (Element, child of assembly)
- Description: Configures deployment behavior, such as updates and system exposure.
- Attributes:
- install (type: boolean, optional): Indicates if installation is required (e.g., "false").
- minimumRequiredVersion (type: string, optional): Minimum version required.
- mapFileExtensions (type: boolean, optional): Enables file extension mapping (e.g., "true").
- disallowUrlActivation (type: boolean, optional): Disallows URL-based activation.
- trustUrlParameters (type: boolean, optional): Trusts URL parameters.
- Required: No.
compatibleFrameworks (Element, child of assembly)
- Description: Specifies compatible .NET Framework versions for installation and execution.
- Attributes:
- SupportUrl (type: string, optional): URL for framework support information.
- Required: Yes.
dependency (Element, child of assembly)
- Description: Defines dependencies on other assemblies, including location and version.
- Attributes:
- preRequisite (type: boolean, optional): Indicates if the dependency is a prerequisite.
- visible (type: boolean, optional): Determines visibility in the user interface.
- dependencyType (type: string, optional): Type of dependency (e.g., "install").
- codebase (type: string, optional): Path to the dependent manifest (e.g., "ContosoOfficeSolutions.dll.manifest").
- size (type: integer, optional): Size of the dependency in bytes (e.g., 13545).
- Required: Yes.
- Child elements (typically):
- dependentAssembly (Element)
- Description: Details a specific dependent assembly.
- Attributes: Same as dependency attributes.
- Child elements:
- assemblyIdentity (as above).
- hash (Element)
- Description: Cryptographic hash for integrity verification.
- Child elements:
- dsig:Transforms (Element): List of transformations.
- dsig:Transform (Element, attribute Algorithm: string, required): Transformation algorithm (e.g., "urn:schemas-microsoft-com:HashTransforms.Identity").
- dsig:DigestMethod (Element, attribute Algorithm: string, required): Digest algorithm (e.g., "http://www.w3.org/2000/09/xmldsig#sha1").
- dsig:DigestValue (Element, text content: string, required): Hash value.
publisherIdentity (Element, child of assembly)
- Description: Identifies the publisher for signed manifests.
- Attributes:
- Name (type: string, required): Publisher name.
- issuerKeyHash (type: string, required): Hash of the issuer's key.
- Required: Yes for signed manifests.
Signature (Element, child of assembly)
- Description: Contains digital signature information for manifest authentication.
- Attributes: None.
- Required: No.
- Child elements (complex structure):
- SignedInfo (Element): Signed data info.
- CanonicalizationMethod (Element, attribute Algorithm: string): Canonicalization algorithm.
- SignatureMethod (Element, attribute Algorithm: string): Signature algorithm.
- Reference (Element): Referenced content.
- Transforms (Element): Transformations.
- Transform (Element, attribute Algorithm: string): Transformation algorithm.
- DigestMethod (Element, attribute Algorithm: string): Digest algorithm.
- DigestValue (Element, text content: string): Digest value.
- SignatureValue (Element, text content: string): Signature value.
- KeyInfo (Element): Key information.
- KeyValue (Element): Key value.
- RSAKeyValue (Element): RSA key.
- Modulus (Element, text content: string): Modulus.
- Exponent (Element, text content: string): Exponent.
- msrel:RelData (Element): Related data for license.
- r:license (Element): License grant.
- r:grant (Element): Grant details.
- as:ManifestInformation (Element, attributes Hash, Description, Url): Manifest info.
- as:assemblyIdentity (as above).
- as:SignedBy (Element): Signer.
- as:AuthenticodePublisher (Element): Publisher.
- as:X509SubjectName (Element, text content: string): Subject name.
- r:issuer (Element): Issuer.
- Signature (nested, similar structure as above).
- X509Data (Element): X509 data.
- X509Certificate (Element, text content: string): Certificate.
customErrorReporting (Element, child of assembly)
- Description: Specifies a URI for error reporting.
- Attributes:
- Uri (type: string, required): Error reporting URI.
- Required: No.
Additionally, the file includes namespace declarations (xmlns attributes) for schemas like asm.v1, asm.v2, dsig, etc., and an XML declaration for version and encoding.
2. Two Direct Download Links for .VSTO Files
After searching, direct public download links for .VSTO files are uncommon, as they are often part of proprietary installations or archives. However, the following are direct links to sample .VSTO files from public sources (note: these may require extraction from zips or may be archived):
- https://code.msdn.microsoft.com/VSTO3MSI/Release/ProjectZip.aspx?ReleaseId=2152 (VSTO installer sample zip containing Sample.vsto; archive link, download the zip to access the file).
- http://clear-lines.com/wiki/Anakin.ashx (Add-in code download containing a VSTO manifest file; downloads as a zip or direct file).
3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .VSTO File Analysis
The following is a self-contained HTML page with embedded JavaScript that allows a user to drag and drop a .VSTO file. It reads the file as text, parses it as XML, extracts the properties from the list above, and dumps them to the screen in a structured format. This can be embedded in a Ghost blog post as an HTML snippet.
4. Python Class for .VSTO File Handling
The following Python class uses xml.etree.ElementTree to open, parse (decode), read, print, and write .VSTO files. The write method allows modifying a property (e.g., version) and saving the file.
import xml.etree.ElementTree as ET
class VSTOHandler:
def __init__(self, filepath):
self.filepath = filepath
self.tree = None
self.root = None
self.namespaces = {
'asmv1': 'urn:schemas-microsoft-com:asm.v1',
'asmv2': 'urn:schemas-microsoft-com:asm.v2',
'dsig': 'http://www.w3.org/2000/09/xmldsig#'
}
def open_and_decode(self):
self.tree = ET.parse(self.filepath)
self.root = self.tree.getroot()
def read_and_print_properties(self):
if not self.root:
print("File not opened. Call open_and_decode first.")
return
props = {}
# assembly
props['assembly'] = {'manifestVersion': self.root.get('manifestVersion')}
# assemblyIdentity
assembly_id = self.root.find('asmv1:assemblyIdentity', self.namespaces)
if assembly_id is not None:
props['assemblyIdentity'] = {k: assembly_id.get(k) for k in ['name', 'version', 'publicKeyToken', 'language', 'processorArchitecture', 'type']}
# description
desc = self.root.find('asmv1:description', self.namespaces)
if desc is not None:
props['description'] = {k: desc.get(f'asmv2:{k}') for k in ['publisher', 'product', 'supportUrl'] if desc.get(f'asmv2:{k}')}
# deployment
deploy = self.root.find('asmv2:deployment', self.namespaces)
if deploy is not None:
props['deployment'] = {k: deploy.get(k) for k in ['install', 'minimumRequiredVersion', 'mapFileExtensions', 'disallowUrlActivation', 'trustUrlParameters']}
# compatibleFrameworks
compat = self.root.find('asmv2:compatibleFrameworks', self.namespaces)
if compat is not None:
props['compatibleFrameworks'] = {'SupportUrl': compat.get('SupportUrl')}
# dependency
dep = self.root.find('asmv2:dependency', self.namespaces)
if dep is not None:
props['dependency'] = {k: dep.get(k) for k in ['preRequisite', 'visible', 'dependencyType', 'codebase', 'size']}
dep_asm = dep.find('asmv2:dependentAssembly', self.namespaces)
if dep_asm is not None:
props['dependency']['dependentAssembly'] = {k: dep_asm.get(k) for k in ['dependencyType', 'codebase', 'size']}
dep_id = dep_asm.find('asmv1:assemblyIdentity', self.namespaces)
if dep_id is not None:
props['dependency']['dependentAssembly']['assemblyIdentity'] = {k: dep_id.get(k) for k in ['name', 'version', 'publicKeyToken', 'language', 'processorArchitecture', 'type']}
hash_elem = dep_asm.find('asmv2:hash', self.namespaces)
if hash_elem is not None:
digest_value = hash_elem.find('dsig:DigestValue', self.namespaces)
if digest_value is not None:
props['dependency']['dependentAssembly']['hash'] = {'digestValue': digest_value.text}
# publisherIdentity
pub_id = self.root.find('asmv2:publisherIdentity', self.namespaces)
if pub_id is not None:
props['publisherIdentity'] = {k: pub_id.get(k) for k in ['name', 'issuerKeyHash']}
# Signature
sig = self.root.find('dsig:Signature', self.namespaces)
if sig is not None:
props['signature'] = {'present': True}
# customErrorReporting
custom_err = self.root.find('asmv2:customErrorReporting', self.namespaces)
if custom_err is not None:
props['customErrorReporting'] = {'Uri': custom_err.get('Uri')}
print("VSTO Properties:")
for key, value in props.items():
print(f"{key}: {value}")
def write_property(self, element_path, attribute, new_value):
if not self.root:
print("File not opened. Call open_and_decode first.")
return
elem = self.root.find(element_path, self.namespaces)
if elem is not None:
elem.set(attribute, new_value)
self.tree.write(self.filepath + '.modified', encoding='utf-8', xml_declaration=True)
print("File written with modified property.")
else:
print("Element not found.")
# Example usage:
# handler = VSTOHandler('sample.vsto')
# handler.open_and_decode()
# handler.read_and_print_properties()
# handler.write_property('asmv1:assemblyIdentity', 'version', '2.0.0.0') # Modify version
5. Java Class for .VSTO File Handling
The following Java class uses javax.xml.parsers to open, parse, read, print, and write .VSTO files. The write method allows modifying a property and saving.
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
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 java.io.File;
public class VSTOHandler {
private String filepath;
private Document doc;
public VSTOHandler(String filepath) {
this.filepath = filepath;
}
public void openAndDecode() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(filepath);
}
public void readAndPrintProperties() throws Exception {
if (doc == null) {
System.out.println("File not opened. Call openAndDecode first.");
return;
}
System.out.println("VSTO Properties:");
// assembly
Element root = doc.getDocumentElement();
System.out.println("assembly: manifestVersion = " + root.getAttribute("manifestVersion"));
// assemblyIdentity
NodeList assemblyIds = doc.getElementsByTagNameNS("urn:schemas-microsoft-com:asm.v1", "assemblyIdentity");
if (assemblyIds.getLength() > 0) {
Element assemblyId = (Element) assemblyIds.item(0);
System.out.println("assemblyIdentity: name = " + assemblyId.getAttribute("name") +
", version = " + assemblyId.getAttribute("version") +
", publicKeyToken = " + assemblyId.getAttribute("publicKeyToken") +
", processorArchitecture = " + assemblyId.getAttribute("processorArchitecture") +
", language = " + assemblyId.getAttribute("language") +
", type = " + assemblyId.getAttribute("type"));
}
// description
NodeList descs = doc.getElementsByTagNameNS("urn:schemas-microsoft-com:asm.v1", "description");
if (descs.getLength() > 0) {
Element desc = (Element) descs.item(0);
System.out.println("description: publisher = " + desc.getAttributeNS("urn:schemas-microsoft-com:asm.v2", "publisher") +
", product = " + desc.getAttributeNS("urn:schemas-microsoft-com:asm.v2", "product") +
", supportUrl = " + desc.getAttributeNS("urn:schemas-microsoft-com:asm.v2", "supportUrl"));
}
// deployment
NodeList deploys = doc.getElementsByTagName("deployment");
if (deploys.getLength() > 0) {
Element deploy = (Element) deploys.item(0);
System.out.println("deployment: install = " + deploy.getAttribute("install") +
", minimumRequiredVersion = " + deploy.getAttribute("minimumRequiredVersion") +
", mapFileExtensions = " + deploy.getAttribute("mapFileExtensions") +
", disallowUrlActivation = " + deploy.getAttribute("disallowUrlActivation") +
", trustUrlParameters = " + deploy.getAttribute("trustUrlParameters"));
}
// compatibleFrameworks
NodeList compats = doc.getElementsByTagName("compatibleFrameworks");
if (compats.getLength() > 0) {
Element compat = (Element) compats.item(0);
System.out.println("compatibleFrameworks: SupportUrl = " + compat.getAttribute("SupportUrl"));
}
// dependency
NodeList deps = doc.getElementsByTagName("dependency");
if (deps.getLength() > 0) {
Element dep = (Element) deps.item(0);
System.out.println("dependency: preRequisite = " + dep.getAttribute("preRequisite") +
", visible = " + dep.getAttribute("visible") +
", dependencyType = " + dep.getAttribute("dependencyType") +
", codebase = " + dep.getAttribute("codebase") +
", size = " + dep.getAttribute("size"));
NodeList depAsms = dep.getElementsByTagName("dependentAssembly");
if (depAsms.getLength() > 0) {
Element depAsm = (Element) depAsms.item(0);
System.out.println("dependentAssembly: dependencyType = " + depAsm.getAttribute("dependencyType") +
", codebase = " + depAsm.getAttribute("codebase") +
", size = " + depAsm.getAttribute("size"));
NodeList depIds = depAsm.getElementsByTagNameNS("urn:schemas-microsoft-com:asm.v1", "assemblyIdentity");
if (depIds.getLength() > 0) {
Element depId = (Element) depIds.item(0);
System.out.println("dependentAssembly assemblyIdentity: name = " + depId.getAttribute("name") +
", version = " + depId.getAttribute("version") +
", publicKeyToken = " + depId.getAttribute("publicKeyToken") +
", processorArchitecture = " + depId.getAttribute("processorArchitecture") +
", language = " + depId.getAttribute("language") +
", type = " + depId.getAttribute("type"));
}
NodeList hashes = depAsm.getElementsByTagName("hash");
if (hashes.getLength() > 0) {
Element hash = (Element) hashes.item(0);
NodeList digestValues = hash.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "DigestValue");
if (digestValues.getLength() > 0) {
System.out.println("dependentAssembly hash: digestValue = " + digestValues.item(0).getTextContent());
}
}
}
}
// publisherIdentity
NodeList pubIds = doc.getElementsByTagName("publisherIdentity");
if (pubIds.getLength() > 0) {
Element pubId = (Element) pubIds.item(0);
System.out.println("publisherIdentity: Name = " + pubId.getAttribute("name") +
", issuerKeyHash = " + pubId.getAttribute("issuerKeyHash"));
}
// Signature
NodeList sigs = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
if (sigs.getLength() > 0) {
System.out.println("signature: present = true");
}
// customErrorReporting
NodeList customErrs = doc.getElementsByTagName("customErrorReporting");
if (customErrs.getLength() > 0) {
Element customErr = (Element) customErrs.item(0);
System.out.println("customErrorReporting: Uri = " + customErr.getAttribute("Uri"));
}
}
public void writeProperty(String tagName, String namespace, String attribute, String newValue) throws Exception {
if (doc == null) {
System.out.println("File not opened. Call openAndDecode first.");
return;
}
NodeList elements = doc.getElementsByTagNameNS(namespace, tagName);
if (elements.getLength() > 0) {
Element elem = (Element) elements.item(0);
elem.setAttribute(attribute, newValue);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filepath + ".modified"));
transformer.transform(source, result);
System.out.println("File written with modified property.");
} else {
System.out.println("Element not found.");
}
}
// Example usage:
// public static void main(String[] args) throws Exception {
// VSTOHandler handler = new VSTOHandler("sample.vsto");
// handler.openAndDecode();
// handler.readAndPrintProperties();
// handler.writeProperty("assemblyIdentity", "urn:schemas-microsoft-com:asm.v1", "version", "2.0.0.0");
// }
}
6. JavaScript Class for .VSTO File Handling
The following JavaScript class (for Node.js, requiring fs and xmldom) opens, parses, reads, prints, and writes .VSTO files. Install xmldom via npm if needed.
const fs = require('fs');
const DOMParser = require('xmldom').DOMParser;
const XMLSerializer = require('xmldom').XMLSerializer;
class VSTOHandler {
constructor(filepath) {
this.filepath = filepath;
this.doc = null;
this.namespaces = {
asmv1: 'urn:schemas-microsoft-com:asm.v1',
asmv2: 'urn:schemas-microsoft-com:asm.v2',
dsig: 'http://www.w3.org/2000/09/xmldsig#'
};
}
openAndDecode() {
const xmlString = fs.readFileSync(this.filepath, 'utf8');
const parser = new DOMParser();
this.doc = parser.parseFromString(xmlString, 'application/xml');
}
readAndPrintProperties() {
if (!this.doc) {
console.log('File not opened. Call openAndDecode first.');
return;
}
const props = {};
// assembly
const root = this.doc.documentElement;
props.assembly = { manifestVersion: root.getAttribute('manifestVersion') };
// assemblyIdentity
const assemblyId = root.getElementsByTagNameNS(this.namespaces.asmv1, 'assemblyIdentity')[0];
if (assemblyId) {
props.assemblyIdentity = {
name: assemblyId.getAttribute('name'),
version: assemblyId.getAttribute('version'),
publicKeyToken: assemblyId.getAttribute('publicKeyToken'),
processorArchitecture: assemblyId.getAttribute('processorArchitecture'),
language: assemblyId.getAttribute('language'),
type: assemblyId.getAttribute('type')
};
}
// description
const desc = root.getElementsByTagNameNS(this.namespaces.asmv1, 'description')[0];
if (desc) {
props.description = {
publisher: desc.getAttributeNS(this.namespaces.asmv2, 'publisher'),
product: desc.getAttributeNS(this.namespaces.asmv2, 'product'),
supportUrl: desc.getAttributeNS(this.namespaces.asmv2, 'supportUrl')
};
}
// deployment
const deploy = root.getElementsByTagName('deployment')[0];
if (deploy) {
props.deployment = {
install: deploy.getAttribute('install'),
minimumRequiredVersion: deploy.getAttribute('minimumRequiredVersion'),
mapFileExtensions: deploy.getAttribute('mapFileExtensions'),
disallowUrlActivation: deploy.getAttribute('disallowUrlActivation'),
trustUrlParameters: deploy.getAttribute('trustUrlParameters')
};
}
// compatibleFrameworks
const compat = root.getElementsByTagName('compatibleFrameworks')[0];
if (compat) {
props.compatibleFrameworks = { SupportUrl: compat.getAttribute('SupportUrl') };
}
// dependency
const dep = root.getElementsByTagName('dependency')[0];
if (dep) {
props.dependency = {
preRequisite: dep.getAttribute('preRequisite'),
visible: dep.getAttribute('visible'),
dependencyType: dep.getAttribute('dependencyType'),
codebase: dep.getAttribute('codebase'),
size: dep.getAttribute('size')
};
const depAsm = dep.getElementsByTagName('dependentAssembly')[0];
if (depAsm) {
props.dependency.dependentAssembly = {
dependencyType: depAsm.getAttribute('dependencyType'),
codebase: depAsm.getAttribute('codebase'),
size: depAsm.getAttribute('size')
};
const depId = depAsm.getElementsByTagNameNS(this.namespaces.asmv1, 'assemblyIdentity')[0];
if (depId) {
props.dependency.dependentAssembly.assemblyIdentity = {
name: depId.getAttribute('name'),
version: depId.getAttribute('version'),
publicKeyToken: depId.getAttribute('publicKeyToken'),
processorArchitecture: depId.getAttribute('processorArchitecture'),
language: depId.getAttribute('language'),
type: depId.getAttribute('type')
};
}
const hash = depAsm.getElementsByTagName('hash')[0];
if (hash) {
const digestValue = hash.getElementsByTagNameNS(this.namespaces.dsig, 'DigestValue')[0];
if (digestValue) {
props.dependency.dependentAssembly.hash = { digestValue: digestValue.textContent };
}
}
}
}
// publisherIdentity
const pubId = root.getElementsByTagName('publisherIdentity')[0];
if (pubId) {
props.publisherIdentity = {
name: pubId.getAttribute('name'),
issuerKeyHash: pubId.getAttribute('issuerKeyHash')
};
}
// Signature
const sig = root.getElementsByTagNameNS(this.namespaces.dsig, 'Signature')[0];
if (sig) {
props.signature = { present: true };
}
// customErrorReporting
const customErr = root.getElementsByTagName('customErrorReporting')[0];
if (customErr) {
props.customErrorReporting = { Uri: customErr.getAttribute('Uri') };
}
console.log('VSTO Properties:');
console.log(JSON.stringify(props, null, 2));
}
writeProperty(tagName, namespace, attribute, newValue) {
if (!this.doc) {
console.log('File not opened. Call openAndDecode first.');
return;
}
const elements = this.doc.getElementsByTagNameNS(namespace, tagName);
if (elements.length > 0) {
elements[0].setAttribute(attribute, newValue);
const serializer = new XMLSerializer();
const xmlString = serializer.serializeToString(this.doc);
fs.writeFileSync(this.filepath + '.modified', xmlString);
console.log('File written with modified property.');
} else {
console.log('Element not found.');
}
}
}
// Example usage:
// const handler = new VSTOHandler('sample.vsto');
// handler.openAndDecode();
// handler.readAndPrintProperties();
// handler.writeProperty('assemblyIdentity', 'urn:schemas-microsoft-com:asm.v1', 'version', '2.0.0.0');
7. C Class for .VSTO File Handling
C does not have built-in classes like object-oriented languages, so the following is a struct with functions (using libxml2 for XML parsing; assume libxml2 is included in the environment). Compile with gcc -o vsto_handler vsto_handler.c pkg-config --cflags --libs libxml-2.0``. The functions open, parse, read, print, and write.
#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
typedef struct {
const char *filepath;
xmlDocPtr doc;
} VSTOHandler;
void vsto_open_and_decode(VSTOHandler *handler) {
handler->doc = xmlParseFile(handler->filepath);
if (handler->doc == NULL) {
printf("Error parsing file.\n");
}
}
void vsto_read_and_print_properties(VSTOHandler *handler) {
if (handler->doc == NULL) {
printf("File not opened. Call vsto_open_and_decode first.\n");
return;
}
xmlNodePtr root = xmlDocGetRootElement(handler->doc);
if (root == NULL) {
printf("Empty document.\n");
return;
}
printf("VSTO Properties:\n");
// assembly
printf("assembly: manifestVersion = %s\n", xmlGetProp(root, (const xmlChar*)"manifestVersion"));
// assemblyIdentity
xmlNodePtr cur = root->children;
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar*)"assemblyIdentity") == 0) {
printf("assemblyIdentity: name = %s, version = %s, publicKeyToken = %s, processorArchitecture = %s, language = %s, type = %s\n",
xmlGetProp(cur, (const xmlChar*)"name"),
xmlGetProp(cur, (const xmlChar*)"version"),
xmlGetProp(cur, (const xmlChar*)"publicKeyToken"),
xmlGetProp(cur, (const xmlChar*)"processorArchitecture"),
xmlGetProp(cur, (const xmlChar*)"language"),
xmlGetProp(cur, (const xmlChar*)"type"));
} else if (xmlStrcmp(cur->name, (const xmlChar*)"description") == 0) {
printf("description: publisher = %s, product = %s, supportUrl = %s\n",
xmlGetNsProp(cur, (const xmlChar*)"publisher", (const xmlChar*)"urn:schemas-microsoft-com:asm.v2"),
xmlGetNsProp(cur, (const xmlChar*)"product", (const xmlChar*)"urn:schemas-microsoft-com:asm.v2"),
xmlGetNsProp(cur, (const xmlChar*)"supportUrl", (const xmlChar*)"urn:schemas-microsoft-com:asm.v2"));
} else if (xmlStrcmp(cur->name, (const xmlChar*)"deployment") == 0) {
printf("deployment: install = %s, minimumRequiredVersion = %s, mapFileExtensions = %s, disallowUrlActivation = %s, trustUrlParameters = %s\n",
xmlGetProp(cur, (const xmlChar*)"install"),
xmlGetProp(cur, (const xmlChar*)"minimumRequiredVersion"),
xmlGetProp(cur, (const xmlChar*)"mapFileExtensions"),
xmlGetProp(cur, (const xmlChar*)"disallowUrlActivation"),
xmlGetProp(cur, (const xmlChar*)"trustUrlParameters"));
} else if (xmlStrcmp(cur->name, (const xmlChar*)"compatibleFrameworks") == 0) {
printf("compatibleFrameworks: SupportUrl = %s\n", xmlGetProp(cur, (const xmlChar*)"SupportUrl"));
} else if (xmlStrcmp(cur->name, (const xmlChar*)"dependency") == 0) {
printf("dependency: preRequisite = %s, visible = %s, dependencyType = %s, codebase = %s, size = %s\n",
xmlGetProp(cur, (const xmlChar*)"preRequisite"),
xmlGetProp(cur, (const xmlChar*)"visible"),
xmlGetProp(cur, (const xmlChar*)"dependencyType"),
xmlGetProp(cur, (const xmlChar*)"codebase"),
xmlGetProp(cur, (const xmlChar*)"size"));
xmlNodePtr depChild = cur->children;
while (depChild != NULL) {
if (xmlStrcmp(depChild->name, (const xmlChar*)"dependentAssembly") == 0) {
printf("dependentAssembly: dependencyType = %s, codebase = %s, size = %s\n",
xmlGetProp(depChild, (const xmlChar*)"dependencyType"),
xmlGetProp(depChild, (const xmlChar*)"codebase"),
xmlGetProp(depChild, (const xmlChar*)"size"));
xmlNodePtr asmChild = depChild->children;
while (asmChild != NULL) {
if (xmlStrcmp(asmChild->name, (const xmlChar*)"assemblyIdentity") == 0) {
printf("dependentAssembly assemblyIdentity: name = %s, version = %s, publicKeyToken = %s, processorArchitecture = %s, language = %s, type = %s\n",
xmlGetProp(asmChild, (const xmlChar*)"name"),
xmlGetProp(asmChild, (const xmlChar*)"version"),
xmlGetProp(asmChild, (const xmlChar*)"publicKeyToken"),
xmlGetProp(asmChild, (const xmlChar*)"processorArchitecture"),
xmlGetProp(asmChild, (const xmlChar*)"language"),
xmlGetProp(asmChild, (const xmlChar*)"type"));
} else if (xmlStrcmp(asmChild->name, (const xmlChar*)"hash") == 0) {
xmlNodePtr hashChild = asmChild->children;
while (hashChild != NULL) {
if (xmlStrcmp(hashChild->name, (const xmlChar*)"DigestValue") == 0) {
printf("dependentAssembly hash: digestValue = %s\n", (char*)hashChild->children->content);
}
hashChild = hashChild->next;
}
}
asmChild = asmChild->next;
}
}
depChild = depChild->next;
}
} else if (xmlStrcmp(cur->name, (const xmlChar*)"publisherIdentity") == 0) {
printf("publisherIdentity: name = %s, issuerKeyHash = %s\n",
xmlGetProp(cur, (const xmlChar*)"name"),
xmlGetProp(cur, (const xmlChar*)"issuerKeyHash"));
} else if (xmlStrcmp(cur->name, (const xmlChar*)"Signature") == 0) {
printf("signature: present = true\n");
} else if (xmlStrcmp(cur->name, (const xmlChar*)"customErrorReporting") == 0) {
printf("customErrorReporting: Uri = %s\n", xmlGetProp(cur, (const xmlChar*)"Uri"));
}
cur = cur->next;
}
}
void vsto_write_property(VSTOHandler *handler, const char *tagName, const char *namespace, const char *attribute, const char *newValue) {
if (handler->doc == NULL) {
printf("File not opened. Call vsto_open_and_decode first.\n");
return;
}
xmlNsPtr ns = xmlSearchNsByHref(handler->doc, xmlDocGetRootElement(handler->doc), (const xmlChar*)namespace);
xmlNodePtr cur = root->children;
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar*)tagName) == 0 && cur->ns == ns) {
xmlSetProp(cur, (const xmlChar*)attribute, (const xmlChar*)newValue);
char modifiedPath[256];
snprintf(modifiedPath, sizeof(modifiedPath), "%s.modified", handler->filepath);
xmlSaveFormatFileEnc(modifiedPath, handler->doc, "UTF-8", 1);
printf("File written with modified property.\n");
return;
}
cur = cur->next;
}
printf("Element not found.\n");
}
void vsto_free(VSTOHandler *handler) {
if (handler->doc != NULL) {
xmlFreeDoc(handler->doc);
}
}
// Example usage:
// int main() {
// VSTOHandler handler = {.filepath = "sample.vsto", .doc = NULL};
// vsto_open_and_decode(&handler);
// vsto_read_and_print_properties(&handler);
// vsto_write_property(&handler, "assemblyIdentity", "urn:schemas-microsoft-com:asm.v1", "version", "2.0.0.0");
// vsto_free(&handler);
// return 0;
// }