Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » XML » Utilities » Downloads
 
Add your own
alternative version

XML Schema Reader Writer Plugin for VS 2005/2008

, 17 Apr 2009 CPOL
Schema based XML reader writer implemented as .NET COM generator
Plugin_setup.zip
setup.exe
xsdAddinSetup.msi
Test_project.zip
jjjjjjjjjjjjj
Properties
Resources
Test.csproj.user
Test.suo
XmlSchemaAddon_src.zip
CodeWrapperGenerator
ICSharpCode.NRefactory.dll
Properties
PostInstaller
Properties
Resources
XmlSchemaAddon.AddIn
PrintLIBID
PrintLIBID.suo
Properties
XmlSchemaAddon.suo
XmlSchemaAddon
ICSharpCode.NRefactory.dll
Properties
Resources
XmlSchemaAddon.AddIn
XmlSchemaAddon.csproj.user
xsdAddinSetup
Release
xsdAddinSetup.vdproj
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;

namespace XmlSchemaAddon
{
     /// <summary>
    /// Specifies project code languages
    /// </summary>
    internal enum ProjectLanguage
    {
        /// <summary>
        /// C# language
        /// </summary>
        CS,
        /// <summary>
        /// J# language
        /// </summary>
        JS,
        /// <summary>
        /// VB.net language
        /// </summary>
        VB,
        /// <summary>
        /// Non supported language
        /// </summary>
        Other
    }


  
    internal partial class XmlSchemaWizard : Form
    {

#region  Internal types
        /// <summary>
        /// Wraps Visual studio project object
        /// </summary>
        internal class ProjectObject
        {
            EnvDTE.Project m_project;

            /// <summary>
            /// Construct a ProjectObject instance.
            /// </summary>
            /// <param name="project">The project to wrap</param>
            internal ProjectObject(EnvDTE.Project project)
            {
                m_project = project;
            }

            /// <summary>
            /// Gets or sets the project
            /// </summary>
            internal EnvDTE.Project Project
            {
                get { return m_project; }
                set { m_project = value; }
            }

            public override string ToString()
            {
                return m_project.Name;
            }

        }


        /// <summary>
        /// Wraps schema file object
        /// </summary>
        internal class SchemaFile
        {
            FileInfo m_file;

            /// <summary>
            /// Construct a SchemaFile instance.
            /// </summary>
            /// <param name="schemaFile">The file  to wrap</param>
            internal SchemaFile(FileInfo schemaFile)
            {
              m_file = schemaFile;
            }

            /// <summary>
            /// Gets or sets the file
            /// </summary>
            internal FileInfo File
            {
                get { return m_file; }
                set { m_file = value; }
            }

            public override string ToString()
            {
                return m_file.Name;
            }

        }

#endregion

#region private members
        /// <summary>
        /// Represents the current solution is the IDE.
        /// </summary>
        EnvDTE.Solution m_vsSolution;

        /// <summary>
        /// Path to the XSD.exe tool
        /// </summary>
        string m_xsdToolPath;

        string m_regasmPath;

#endregion

#region public form events

        public XmlSchemaWizard(EnvDTE.Solution vsSolution)
        {
            InitializeComponent();

            m_vsSolution = vsSolution;

            string sdkDir = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Microsoft SDKs\Windows", "CurrentInstallFolder", null) as string;
            if (sdkDir == null) return;

            m_xsdToolPath = sdkDir + "bin" + Path.DirectorySeparatorChar +
                            "xsd.exe";

            m_regasmPath = Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework", "InstallRoot", null) as string;
            m_regasmPath += "v2.0.50727" + Path.DirectorySeparatorChar + "regasm.exe";
        }

        private void XmlSchemaWizard_Load(object sender, EventArgs e)
        {
            if( m_vsSolution == null || ! m_vsSolution.IsOpen ){
                MessageBox.Show(this, "Development environment has no active solution", "Can't generate XML schema proxy", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Close();
                return;
            }

            if (m_vsSolution.Projects == null || m_vsSolution.Projects.Count < 1){
                MessageBox.Show(this, "The current solution contains no projects", "Can't generate XML schema proxy", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Close();
                return;
            }
                
            if( m_xsdToolPath == null || ! File.Exists(m_xsdToolPath) ) {
                MessageBox.Show(this, "Microsoft Windows SDK 6.0 and above is required", "Can't locate Microsoft xsd.exe tool", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Close();
                return;
            }

            if (m_regasmPath == null || !File.Exists(m_regasmPath))
                m_regasmPath = null;
            
            PopulateUiData();
            
        }

        private void checkBoxGenDll_CheckedChanged(object sender, EventArgs e)
        {
            UpdateUI();
        }

        private void checkBoxRegDll_CheckedChanged(object sender, EventArgs e)
        {
            UpdateUI();
        }

        private void checkBoxGenCode_CheckedChanged(object sender, EventArgs e)
        {
            UpdateUI();
        }


        private void buttonGenFactoryGuid_Click(object sender, EventArgs e)
        {
            textBoxFactoryClassGuid.Text = Guid.NewGuid().ToString().ToUpper();
        }

        private void buttonGenFactoryInterfaceGuid_Click(object sender, EventArgs e)
        {
            textBoxFactoryInterfaceGuid.Text = Guid.NewGuid().ToString().ToUpper();
        }

        private void buttonExecute_Click(object sender, EventArgs e)
        {
            if( textBoxNamespace.Text.Length < 1 ){
                MessageBox.Show(this, "Namespace for the generated code must be entered.","Missing namespace",  MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (textBoxNamespace.Text.Contains(" ") ) {
                MessageBox.Show(this, "Space characters can't be used for a namespace.", "Invalid namespace", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if( checkBoxGenDll.Enabled )
            {
                SchemaFile file = comboBoxSelSchema.SelectedItem as SchemaFile;
                if( ! GenerateClassLibraryForSchema(textBoxAssemblyName.Text, textBoxNamespace.Text, file.File) )
                    MessageBox.Show(this, "Failed generating class library.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                    MessageBox.Show(this, "Class library created successfully.", "Done", MessageBoxButtons.OK, MessageBoxIcon.None);
            }

            Close();
        }

        

        private void comboBoxSelProject_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxSelProject.SelectedIndex < 0)
            {
                toolTipXmlWizard.SetToolTip(comboBoxSelProject, "Select project from the current solution to add the XML schema objects to.");
                UpdateUI();
                return;
            }

            ProjectObject proj = comboBoxSelProject.SelectedItem as ProjectObject;
            toolTipXmlWizard.SetToolTip(comboBoxSelProject, proj.Project.FileName);

            comboBoxSelSchema.Items.Clear();
            List<FileInfo> schemaFiles = IDECodeLibrary.GetProjectFiles(proj.Project, ".xsd");
            foreach (FileInfo file in schemaFiles)
                comboBoxSelSchema.Items.Add(new SchemaFile(file));


            string projNs = IDECodeLibrary.GetProjectDefaultNamespace(proj.Project);
            if (projNs == null) projNs = string.Empty;

            textBoxNamespace.Text = projNs;

            UpdateUI();
        }


        private void comboBoxSelSchema_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxSelSchema.SelectedIndex < 0)
            {
                toolTipXmlWizard.SetToolTip(comboBoxSelSchema, "Select XML schema file from the project.");
                UpdateUI();
                return;
            }

            SchemaFile file = comboBoxSelSchema.SelectedItem as SchemaFile;

            if( ! file.File.Exists )
            {
                MessageBox.Show(this,"Can't locate the file " + file.File.FullName, "Schema file not exist", MessageBoxButtons.OK, MessageBoxIcon.Error);
                comboBoxSelSchema.SelectedIndex = -1;
                return;
            }

            if ( !ValidateSachmaFile(file) )
            {
                MessageBox.Show(this, "The file " + file.File.FullName + " don't contains valid XML schema", "Invalid schema file", MessageBoxButtons.OK, MessageBoxIcon.Error);
                comboBoxSelSchema.SelectedIndex = -1;
                return;
            }   

            toolTipXmlWizard.SetToolTip(comboBoxSelSchema, file.File.FullName);
            textBoxAssemblyName.Text = Path.GetFileNameWithoutExtension(file.File.Name) + ".dll";
            UpdateUI();
        }

#endregion

#region private UI methods

        /// <summary>
        /// Populates the data in the controls
        /// </summary>
        private void PopulateUiData()
        {
            buttonGenFactoryGuid_Click(null, null);
            buttonGenFactoryInterfaceGuid_Click(null, null);

            comboBoxSelProject.Items.Clear();

            foreach ( EnvDTE.Project proj in m_vsSolution.Projects )
                comboBoxSelProject.Items.Add( new ProjectObject( proj ) );
            
            comboBoxSelCodeLanguage.Items.Clear();
            comboBoxSelCodeLanguage.Items.Add(ProjectLanguage.CS);
            comboBoxSelCodeLanguage.Items.Add(ProjectLanguage.VB);            
        }

        private void UpdateUI()
        {
            if (comboBoxSelProject.SelectedIndex < 0 || comboBoxSelSchema.Items.Count == 0)
                comboBoxSelSchema.Visible = false;
            else
                comboBoxSelSchema.Visible = true;

            if (!comboBoxSelSchema.Visible)
            {
                comboBoxSelSchema.Items.Clear();
                comboBoxSelSchema.SelectedIndex = -1;
            }

            labelFactoryGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;
            textBoxFactoryClassGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;
            buttonGenFactoryGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;

            labelFacroryInterfaceGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;
            textBoxFactoryInterfaceGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;
            buttonGenFactoryInterfaceGuid.Visible = comboBoxSelSchema.SelectedIndex > -1;

            labelNamespace.Visible = comboBoxSelSchema.SelectedIndex > -1;
            textBoxNamespace.Visible = comboBoxSelSchema.SelectedIndex > -1;

            checkBoxGenDll.Visible = comboBoxSelSchema.SelectedIndex > -1;
            checkBoxRegDll.Visible = labelAssemblyName.Visible = textBoxAssemblyName.Visible =
                            checkBoxGenDll.Visible && checkBoxGenDll.Checked;

            checkBoxGenerateTLB.Visible = checkBoxRegDll.Visible && checkBoxRegDll.Checked;

            checkBoxGenCode.Visible = comboBoxSelSchema.SelectedIndex > -1;
            comboBoxSelCodeLanguage.Visible = checkBoxGenCode.Visible && checkBoxGenCode.Checked;

            buttonExecute.Enabled = (checkBoxGenDll.Visible && checkBoxGenDll.Checked) ||
                                    (comboBoxSelCodeLanguage.Visible && comboBoxSelCodeLanguage.SelectedIndex > -1);
        }

#endregion

#region private methods

        /// <summary>
        /// Validates the schema file
        /// </summary>
        /// <param name="file">Schema file</param>
        /// <returns>true if valid otherwise false</returns>
         private bool ValidateSachmaFile(SchemaFile file)
         {
             StreamReader stream = null;
             try{
                 stream = file.File.OpenText();
             }
             catch { return false; }

             try
             {
                 System.Xml.Schema.XmlSchema schema = System.Xml.Schema.XmlSchema.Read(stream, null);
             }
             catch
             {
                 return false;
             }
             finally
             {
                 stream.Close();
             }

             return true;
         }

         /// <summary>
         /// Registers the given .NET assembly file using regasm tool.
         /// </summary>
         /// <param name="assemblyPath">The path to the assembly file</param>
         /// <returns>true for success</returns>
         private bool RegisterAssembly(string assemblyPath)
         {
             if (m_regasmPath == null)
             {
                 MessageBox.Show(this, "Cannot locate regasm.exe", "Can't register the generated assembly", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                 return false;
             }

             Process proc = null;

             string cmdArgs = !checkBoxGenerateTLB.Checked ? "\"" + assemblyPath + "\"" :
                                                            "/tlb \"" + assemblyPath + "\"";

             try
             {
                 ProcessStartInfo startInfo = new ProcessStartInfo(m_regasmPath, cmdArgs);
                 startInfo.CreateNoWindow = true;
                 startInfo.UseShellExecute = false;
                 proc = new Process();
                 proc.StartInfo = startInfo;
                 proc.Start();
                 proc.WaitForExit();
             }
             catch { proc = null; }

             return (proc != null && proc.ExitCode == 0);
         }

        /// <summary>
        /// Executes the XSD tool to generate the raw proxy types for the XSD file.
        /// </summary>
        /// <param name="namespaceName">The namespace to create the raw proxy types at</param>
        /// <param name="xsdFile">The schema file</param>
        /// <param name="outputPath">The path of the directory to put the output file</param>
        /// <returns><value>true</value> for success.</returns>
        private bool ExecuteXsdTool(string namespaceName, FileInfo xsdFile, string outputPath)
        {
            
            string xsdCmd = string.Format("\"{0}\" /c /l:{1} /n:{2} \"/o:{3}\"",
                                                                               xsdFile.FullName,
                                                                               "cs",
                                                                               namespaceName,
                                                                               outputPath
                                                                              );
            Process proc = null;

            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo(m_xsdToolPath, xsdCmd);
                startInfo.CreateNoWindow = true;
                startInfo.UseShellExecute = false;
                proc = new Process();
                proc.StartInfo = startInfo;
                proc.Start();
                proc.WaitForExit();
            }
            catch { proc = null; }

            return (proc != null && proc.ExitCode == 0);
        }

        private EnvDTE.Project GetSelectedProject()
        {
            return (comboBoxSelProject.SelectedItem as ProjectObject).Project;
        }

        /// <summary>
        /// Attempts to unregister assembly of a file in the project
        /// </summary>
        /// <param name="fileName">the file name</param>
        private void UnRegisterAssemblyFile(string fileName)
        {
            if (m_regasmPath == null)  return;

            List<FileInfo> allFiles = IDECodeLibrary.GetProjectFiles(GetSelectedProject(), null);

            foreach (FileInfo file in allFiles)
            {
                if (string.Compare(file.Name, fileName, true) != 0) continue;

                Process proc = null;

                try
                {
                    ProcessStartInfo startInfo = new ProcessStartInfo(m_regasmPath, "/u \"" + file.FullName + "\"");
                    startInfo.CreateNoWindow = true;
                    startInfo.UseShellExecute = false;
                    proc = new Process();
                    proc.StartInfo = startInfo;
                    proc.Start();
                    proc.WaitForExit();
                }
                catch {}
            }
        }

        private bool GenerateClassLibraryForSchema(string assemblyName, string namespaceName, FileInfo xsdFile)
        {
            try
            {
                string tempDir = Path.GetTempPath();
                if (tempDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
                    tempDir = tempDir.Substring(0, tempDir.Length - 1);

                Trace.TraceInformation("+Executing xsd.exe" + Environment.NewLine);

                if (!ExecuteXsdTool(namespaceName, xsdFile, tempDir))
                    return false;

                Trace.TraceInformation("-Done executing xsd.exe" + Environment.NewLine);

                Trace.TraceInformation("+Opening proxy classes file" + Environment.NewLine);

                FileInfo proxyObjectsFile = new FileInfo(tempDir + Path.DirectorySeparatorChar + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(xsdFile.Name) + ".cs");
                if (!proxyObjectsFile.Exists) return false;

                StreamReader proxyFile = proxyObjectsFile.OpenText();
                string proxyCode = proxyFile.ReadToEnd();
                proxyFile.Close();

                Trace.TraceInformation("-Done reading proxy classes file" + Environment.NewLine);

                string interfaceCodeFile = Path.GetTempFileName();
                string impCodeFile = Path.GetTempFileName();

                Trace.TraceInformation("+Opennng schema file " + Environment.NewLine);

                StreamReader schemaReader = xsdFile.OpenText();

                Trace.TraceInformation("-Done opennng schema file " + Environment.NewLine);

                Trace.TraceInformation("+Creating com wrapper interfaces file" + Environment.NewLine);

                new XmlSchemaWrapperGen.InterfaceGenerator().CreateComWrapperInterface(new StringReader(proxyCode),
                                                                                       ICSharpCode.NRefactory.SupportedLanguage.CSharp,
                                                                                       new Guid(textBoxFactoryInterfaceGuid.Text),
                                                                                       interfaceCodeFile
                                                                                       );

                Trace.TraceInformation("-Done creating com wrapper interfaces file" + Environment.NewLine);

                Trace.TraceInformation("+Creating com wrapper implementation file" + Environment.NewLine);

                XmlSchemaWrapperGen.ImplementationGenerator impGen = new XmlSchemaWrapperGen.ImplementationGenerator();
                impGen.CreateComWrapper(new StringReader(proxyCode),
                                        ICSharpCode.NRefactory.SupportedLanguage.CSharp,
                                        new Guid(textBoxFactoryClassGuid.Text),
                                        impCodeFile,
                                        schemaReader.ReadToEnd()
                                        );

                schemaReader.Close();

                Trace.TraceInformation("-Done creating com wrapper implementation file" + Environment.NewLine);

                Trace.TraceInformation("+Saving proxy code to file" + Environment.NewLine);

                //Compiling the code:
                StreamWriter sw = new StreamWriter(proxyObjectsFile.FullName, false);
                sw.Write(proxyCode);
                sw.Close();

                Trace.TraceInformation("-Done saving proxy code to file" + Environment.NewLine);

                List<string> sourceFilesList = new List<string>();
                sourceFilesList.Add(proxyObjectsFile.FullName);
                sourceFilesList.Add(interfaceCodeFile);
                sourceFilesList.Add(impCodeFile);

                string xmlDocFilePath = tempDir + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(assemblyName) + ".xml";
                string outputPath = tempDir + Path.DirectorySeparatorChar + assemblyName;
                if (File.Exists(outputPath))
                    File.Delete(outputPath);

                Trace.TraceInformation("+Starting to compile" + Environment.NewLine);

                impGen.CompileCSharpCode(sourceFilesList, outputPath, true);

                Trace.TraceInformation("-Done compiling" + Environment.NewLine);

                string schemaName = Path.GetFileNameWithoutExtension(xsdFile.Name);

                Trace.TraceInformation("+Uneregistering assembly" + Environment.NewLine);

                UnRegisterAssemblyFile(textBoxAssemblyName.Text);

                Trace.TraceInformation("-Done uneregistering assembly" + Environment.NewLine);


                Trace.TraceInformation("+Moving xml documentation to project folder" + Environment.NewLine);

                EnvDTE.ProjectItem libraryFileItem = IDECodeLibrary.MoveFileToProjectFolder(new FileInfo(xmlDocFilePath),
                                                schemaName + "_Objects",
                                                GetSelectedProject()
                                                );

                IDECodeLibrary.SetItemBuildAction(libraryFileItem, IDECodeLibrary.BuildAction.None);

                Trace.TraceInformation("-Done moving xml documentation to project folder" + Environment.NewLine);

                Trace.TraceInformation("+Moving class library to project folder" + Environment.NewLine);

                libraryFileItem = IDECodeLibrary.MoveFileToProjectFolder(new FileInfo(outputPath),
                                                schemaName + "_Objects",
                                                GetSelectedProject()
                                                );                

                Trace.TraceInformation("-Done moving class library to project folder" + Environment.NewLine);

                string asmPath = (string)IDECodeLibrary.GetProjectItemProperty(libraryFileItem,
                                IDECodeLibrary.ProjectItemProperty.FullPath);                
                
                IDECodeLibrary.SetItemBuildAction(libraryFileItem, IDECodeLibrary.BuildAction.None);

                Trace.TraceInformation("+Moving readme file to project folder" + Environment.NewLine);
                
                EnvDTE.ProjectItem readmeFileItem = IDECodeLibrary.MoveFileToProjectFolder(CreateReadmeFile(Path.GetTempPath() + schemaName + ".txt", asmPath),
                                                schemaName + "_Objects",
                                                GetSelectedProject()
                                                );

                Trace.TraceInformation("-Done moving readme file to project folder" + Environment.NewLine);

                IDECodeLibrary.SetItemBuildAction(readmeFileItem, IDECodeLibrary.BuildAction.None);

                Trace.TraceInformation("+Deleting proxy file" + Environment.NewLine);

                proxyObjectsFile.Delete();

                Trace.TraceInformation("-Done deleting proxy file" + Environment.NewLine);

                if( File.Exists(outputPath) )
                    File.Delete(outputPath);

                if (!checkBoxRegDll.Checked) return true;

                Trace.TraceInformation("+Registering assembly file" + Environment.NewLine);

                return RegisterAssembly(asmPath);

            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

       /// <summary>
       /// Generates a read me file for the generated output
       /// </summary>
       /// <param name="filePath">Path to generate the file in.</param>
       /// <param name="generatedAssemblyPath">Path to the generated assembly</param>
       /// <returns>returns the read me file</returns>
       private FileInfo CreateReadmeFile(string filePath, string generatedAssemblyPath)
       {
           FileInfo textFile = new FileInfo( filePath );
           if (textFile.Exists) textFile.Delete();
           StreamWriter writer = textFile.CreateText();

           writer.WriteLine("COM guids specification for COM access:");
           writer.WriteLine();

           string strLibIDPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
           strLibIDPath = Path.GetDirectoryName(strLibIDPath) + Path.DirectorySeparatorChar + "PrintLIBID.exe";

           Process proc = null;
           string libID = null;
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo(strLibIDPath, "\"" + generatedAssemblyPath + "\"");
                startInfo.CreateNoWindow = true;
                startInfo.UseShellExecute = false;
                startInfo.RedirectStandardOutput = true;

                proc = new Process();
                proc.StartInfo = startInfo;
                proc.Start();

                while (!proc.StandardOutput.EndOfStream)
                    libID = proc.StandardOutput.ReadLine();

                proc.WaitForExit();
                if (proc.ExitCode == 0 && libID != null )
                {
                    writer.WriteLine("\tLIBID: {0}", libID);
                    writer.WriteLine();
                }
            }
            catch {}

           
           writer.WriteLine("\tFactory interface COM guid: {0}", textBoxFactoryInterfaceGuid.Text);
           writer.WriteLine();
           writer.WriteLine("\tFactory class COM guid: {0}", textBoxFactoryClassGuid.Text);
           writer.Close();
           return textFile;
       }

#endregion
               

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

JadBenAutho
Software Developer Rontal Applications
Israel Israel
Born and raised in Israel, I've caught the programming virus at the age of 15.
Since than I can't stop coding.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150123.1 | Last Updated 17 Apr 2009
Article Copyright 2009 by JadBenAutho
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid