1

For one of my projects in college I had to create a test as a Word document and add some ActiveX forms in it to be completed by another person. After this I had to programmatically extract the answers from it and put a grade on the test.

I used OpenXML SDK for processing the document, but it gave me headaches because I couldn't find a way to get the ActiveX values.

So what was the solution?

Berkay Turancı
  • 3,373
  • 4
  • 32
  • 45
Andrei Micu
  • 3,159
  • 1
  • 17
  • 20

1 Answers1

3

After searching the Internet and a bit of sniffing on the document I have found that the ActiveX control data can be found in a document part specified by the control ID. Determining the type of control is a bit tricky because I didn't find any documentation about this. Apparently you must get the "classid" attribute from a control and try to match it to the classids you know. Below is the code for determining the values for three types of controls. The rest of the ids are marked as not known and you can match them intuitively to the ones you added in the document.


using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Xml;
using System.IO;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;

namespace OpenXMLTest
{
    class Program
    {
        const string textBoxId = "{8BD21D10-EC42-11CE-9E0D-00AA006002F3}";
        const string radioButtonId = "{8BD21D50-EC42-11CE-9E0D-00AA006002F3}";
        const string checkBoxId = "{8BD21D40-EC42-11CE-9E0D-00AA006002F3}";

        static void Main(string[] args)
        {
            string fileName = @"C:\Users\Andy\Desktop\test_l1demo.docx";
            using (WordprocessingDocument doc = WordprocessingDocument.Open(fileName, false))
            {
                foreach (Control control in doc.MainDocumentPart.Document.Body.Descendants())
                {
                    Console.WriteLine();
                    Console.WriteLine("Control {0}:", control.Name);
                    Console.WriteLine("Id: {0}", control.Id);

                    displayControlDetails(doc, control.Id);
                }
            }

            Console.Read();
        }

        private static void displayControlDetails(WordprocessingDocument doc, StringValue controlId)
        {
            string classId, type, value;

            OpenXmlPart part = doc.MainDocumentPart.GetPartById(controlId);
            OpenXmlReader reader = OpenXmlReader.Create(part.GetStream());
            reader.Read();
            OpenXmlElement controlDetails = reader.LoadCurrentElement();

            classId = controlDetails.GetAttribute("classid", controlDetails.NamespaceUri).Value;

            switch (classId)
            {
                case textBoxId:
                    type = "TextBox";
                    break;
                case radioButtonId:
                    type = "Radio Button";
                    break;
                case checkBoxId:
                    type = "CheckBox";
                    break;
                default:
                    type = "Not known";
                    break;
            }

            value = "No value attribute"; //displays this if there is no "value" attribute found
            foreach (OpenXmlElement child in controlDetails.Elements())
            {
                if (child.GetAttribute("name", controlDetails.NamespaceUri).Value == "Value")
                {
                    //we've found the value typed by the user in this control
                    value = child.GetAttribute("value", controlDetails.NamespaceUri).Value;
                }
            }

            reader.Close();

            Console.WriteLine("Class id: {0}", classId);
            Console.WriteLine("Control type: {0}", type);
            Console.WriteLine("Control value: {0}", value);

        }
    }
}
Andrei Micu
  • 3,159
  • 1
  • 17
  • 20