diff --git a/src/Tools/Help/Help2Register.exe b/src/Tools/Help/Help2Register.exe index 756b61bebe..1dd7d033fa 100644 Binary files a/src/Tools/Help/Help2Register.exe and b/src/Tools/Help/Help2Register.exe differ diff --git a/src/Tools/Help/MSHelpServices.dll b/src/Tools/Help/MSHelpServices.dll index 97a6d34705..aa890731f4 100644 Binary files a/src/Tools/Help/MSHelpServices.dll and b/src/Tools/Help/MSHelpServices.dll differ diff --git a/src/Tools/Help/plugins.xml b/src/Tools/Help/plugins.xml index c92ccae63b..048dd1ee0b 100644 --- a/src/Tools/Help/plugins.xml +++ b/src/Tools/Help/plugins.xml @@ -1,5 +1,5 @@ - + diff --git a/src/Tools/Help/register.xml b/src/Tools/Help/register.xml index c42ee7c22d..26b70eaadf 100644 --- a/src/Tools/Help/register.xml +++ b/src/Tools/Help/register.xml @@ -1,5 +1,5 @@ - + diff --git a/src/Tools/Help/register.xsd b/src/Tools/Help/register.xsd index bc7179d9cf..9f9fb5d2a3 100644 --- a/src/Tools/Help/register.xsd +++ b/src/Tools/Help/register.xsd @@ -1,6 +1,10 @@ - - + Help 2.0 Registration Validation Schema Copyright (c) 2005 Mathias Simmack diff --git a/src/Tools/Help/source/Configuration/AssemblyInfo.cs b/src/Tools/Help/source/Configuration/AssemblyInfo.cs new file mode 100644 index 0000000000..b7550ef4d1 --- /dev/null +++ b/src/Tools/Help/source/Configuration/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("Help 2.0 Registration Utility")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Cube")] +[assembly: AssemblyProduct("Help 2.0 Utilities")] +[assembly: AssemblyCopyright("Copyright (c) 2005 Mathias Simmack")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("3.0.*")] + +// The following attributes specify the key for the sign of your assembly. See the +// .NET Framework documentation for more information about signing. +// This is not required, if you don't want signing let these attributes like they're. +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] + +[assembly: CLSCompliant(false)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)] +[assembly: ComVisibleAttribute(false)] diff --git a/src/Tools/Help/source/CreateMsHelpAssembly.bat b/src/Tools/Help/source/CreateMsHelpAssembly.bat new file mode 100644 index 0000000000..3af8dbd151 --- /dev/null +++ b/src/Tools/Help/source/CreateMsHelpAssembly.bat @@ -0,0 +1,18 @@ +@echo off +setlocal +set AxImp="%ProgramFiles%\Microsoft.NET\SDK\v2.0\Bin\AxImp.exe" +set Help2Library="%CommonProgramFiles%\Microsoft Shared\help\hxvz.dll" + + +if exist Ax*.dll del Ax*.dll +if exist MSHelp*.dll del MSHelp*.dll + +%AxImp% %Help2Library% + +del Ax*.dll +del MSHelpControls.dll + +set Help2Library= +set AxImp= + +pause \ No newline at end of file diff --git a/src/Tools/Help/source/Help2Register.csproj b/src/Tools/Help/source/Help2Register.csproj new file mode 100644 index 0000000000..3f56e270e5 --- /dev/null +++ b/src/Tools/Help/source/Help2Register.csproj @@ -0,0 +1,70 @@ + + + Exe + Help2Register + Help2Register + Release + AnyCPU + {10C38AE6-0491-4677-BA39-5A2A8C704544} + False + True + False + None + False + Auto + 4194304 + AnyCPU + 4096 + 4 + false + false + False + + False + File + + + .. + true + DEBUG;TRACE + + + .. + true + TRACE + + + + + + MSHelpServices.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Tools/Help/source/Help2Register.sln b/src/Tools/Help/source/Help2Register.sln new file mode 100644 index 0000000000..650d959826 --- /dev/null +++ b/src/Tools/Help/source/Help2Register.sln @@ -0,0 +1,16 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# SharpDevelop 2.1.0.1596 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Help2Register", "Help2Register.csproj", "{10C38AE6-0491-4677-BA39-5A2A8C704544}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10C38AE6-0491-4677-BA39-5A2A8C704544}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10C38AE6-0491-4677-BA39-5A2A8C704544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10C38AE6-0491-4677-BA39-5A2A8C704544}.Release|Any CPU.Build.0 = Release|Any CPU + {10C38AE6-0491-4677-BA39-5A2A8C704544}.Release|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/Tools/Help/source/HelperClasses/ApplicationHelpers.cs b/src/Tools/Help/source/HelperClasses/ApplicationHelpers.cs new file mode 100644 index 0000000000..bfa251fee2 --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/ApplicationHelpers.cs @@ -0,0 +1,90 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Security; + using System.Security.Permissions; + using System.Security.Principal; + using System.Threading; + using Microsoft.Win32; + + public sealed class ApplicationHelpers + { + public const string Help2NamespaceUri = "http://www.simmack.de/2006/help2"; + + ApplicationHelpers() + { + } + + public static bool IsClassRegistered(string classId) + { + try + { + RegistryKey tmp = Registry.ClassesRoot.OpenSubKey + (string.Format(CultureInfo.InvariantCulture, @"CLSID\{0}\InprocServer32", classId), false); + string help2Library = (string)tmp.GetValue("", string.Empty); + tmp.Close(); + + return (!string.IsNullOrEmpty(help2Library) && File.Exists(help2Library)); + } + catch (ArgumentException) + { + } + catch (SecurityException) + { + } + return false; + } + + [PermissionSet(SecurityAction.LinkDemand, Name="Execution")] + public static void KillIllegalProcesses(string[] invalidProcesses) + { + if (invalidProcesses == null || invalidProcesses.Length == 0) + { + return; + } + + Process[] runningProcesses = Process.GetProcesses(); + foreach (Process currentProcess in runningProcesses) + { + try + { + string fileName = Path.GetFileName(currentProcess.MainModule.FileName); + foreach (string invalidProcess in invalidProcesses) + { + if (string.Compare(invalidProcess.ToLower(CultureInfo.InvariantCulture), + fileName.ToLower(CultureInfo.InvariantCulture)) == 0) + { + currentProcess.Kill(); + currentProcess.WaitForExit(); + } + } + } + catch (System.ComponentModel.Win32Exception) + { + } + } + } + + public static bool IsThisUserPrivileged() + { + switch(Environment.OSVersion.Platform) + { + case PlatformID.Win32NT: + AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); + WindowsPrincipal wp = (Thread.CurrentPrincipal as WindowsPrincipal); + return (wp.IsInRole(WindowsBuiltInRole.Administrator) || wp.IsInRole(WindowsBuiltInRole.PowerUser)); + case PlatformID.Win32Windows: + return true; + default: + return false; + } + } + } +} diff --git a/src/Tools/Help/source/HelperClasses/MergeNamespaceClass.cs b/src/Tools/Help/source/HelperClasses/MergeNamespaceClass.cs new file mode 100644 index 0000000000..3fbeb861c9 --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/MergeNamespaceClass.cs @@ -0,0 +1,38 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Globalization; + using HtmlHelp2Registration.ItemClasses; + using MSHelpServices; + + public sealed class MergeNamespace + { + MergeNamespace() + { + } + + public static void CallMerge(string namespaceName) + { + try + { + HxSessionClass session = new HxSessionClass(); + session.Initialize(string.Format(CultureInfo.InvariantCulture, "ms-help://{0}", namespaceName), 0); + + // Next lesson about the Help 2.0 API: You have to wait until + // "MergeIndex" is ready. This is a console tool, so ... But + // if you want to do it with a GUI tool, you have to use a + // thread or something. I used a thread in my Delphi version. + + IHxCollection collection = session.Collection; + collection.MergeIndex(); + } + catch (System.Runtime.InteropServices.COMException) + { + } + } + } +} diff --git a/src/Tools/Help/source/HelperClasses/PluginSearchClass.cs b/src/Tools/Help/source/HelperClasses/PluginSearchClass.cs new file mode 100644 index 0000000000..1408847080 --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/PluginSearchClass.cs @@ -0,0 +1,156 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Collections.Specialized; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Runtime.InteropServices; + using MSHelpServices; + + public sealed class PluginSearch + { + PluginSearch() + { + } + + public static bool PluginDoesExist(string namespaceName, string pluginName) + { + if (string.IsNullOrEmpty(namespaceName) || string.IsNullOrEmpty(pluginName)) + { + return false; + } + + try + { + HxRegistryWalkerClass registryWalker = new HxRegistryWalkerClass(); + IHxRegNamespaceList help2Namespaces = registryWalker.get_RegisteredNamespaceList(""); + + foreach (IHxRegNamespace currentNamespace in help2Namespaces) + { + if (string.Compare(currentNamespace.Name, namespaceName) == 0) + { + IHxRegPlugInList p = + (IHxRegPlugInList)currentNamespace.GetProperty(HxRegNamespacePropId.HxRegNamespacePlugInList); + foreach (IHxRegPlugIn plugin in p) + { + string currentName = (string)plugin.GetProperty(HxRegPlugInPropId.HxRegPlugInName); + if (string.Compare(currentName, pluginName) == 0) + { + return true; + } + } + } + } + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public static StringCollection FindPlugin(string pluginName) + { + StringCollection namespaces = new StringCollection(); + try + { + HxRegistryWalkerClass registryWalker = new HxRegistryWalkerClass(); + IHxRegNamespaceList help2Namespaces = registryWalker.get_RegisteredNamespaceList(""); + + foreach (IHxRegNamespace currentNamespace in help2Namespaces) + { + IHxRegPlugInList p = + (IHxRegPlugInList)currentNamespace.GetProperty(HxRegNamespacePropId.HxRegNamespacePlugInList); + foreach (IHxRegPlugIn plugin in p) + { + string currentName = (string)plugin.GetProperty(HxRegPlugInPropId.HxRegPlugInName); + if (string.Compare(currentName, pluginName) == 0) + { + namespaces.Add(currentNamespace.Name); + break; + } + } + } + } + catch (System.Runtime.InteropServices.COMException) + { + } + return namespaces; + } + + public static ReadOnlyCollection FindPluginAsGenericList(string pluginName) + { + List namespaces = new List(); + try + { + HxRegistryWalkerClass registryWalker = new HxRegistryWalkerClass(); + IHxRegNamespaceList help2Namespaces = registryWalker.get_RegisteredNamespaceList(""); + + foreach (IHxRegNamespace currentNamespace in help2Namespaces) + { + IHxRegPlugInList p = + (IHxRegPlugInList)currentNamespace.GetProperty(HxRegNamespacePropId.HxRegNamespacePlugInList); + foreach (IHxRegPlugIn plugin in p) + { + string currentName = (string)plugin.GetProperty(HxRegPlugInPropId.HxRegPlugInName); + if (string.Compare(currentName, pluginName) == 0) + { + namespaces.Add(currentNamespace.Name); + break; + } + } + } + } + catch (System.Runtime.InteropServices.COMException) + { + } + ReadOnlyCollection roNamespaces = new ReadOnlyCollection(namespaces); + return roNamespaces; + } + + public static string GetFirstMatchingNamespaceName(string matchingName) + { + HxRegistryWalkerClass registryWalker; + IHxRegNamespaceList help2Namespaces; + try + { + registryWalker = new HxRegistryWalkerClass(); + help2Namespaces = registryWalker.get_RegisteredNamespaceList(""); + } + catch (System.Runtime.InteropServices.COMException) + { + help2Namespaces = null; + registryWalker = null; + } + + if (registryWalker == null || help2Namespaces == null || help2Namespaces.Count == 0 || string.IsNullOrEmpty(matchingName)) + { + return string.Empty; + } + foreach (IHxRegNamespace currentNamespace in help2Namespaces) + { + if (NativeMethods.PathMatchSpec(currentNamespace.Name, matchingName)) + { + return currentNamespace.Name; + } + } + return help2Namespaces.ItemAt(1).Name; + } + } + + internal class NativeMethods + { + NativeMethods() + { + } + + #region PatchMatchSpec + [DllImport("shlwapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool PathMatchSpec(string pwszFile, string pwszSpec); + #endregion + } +} diff --git a/src/Tools/Help/source/HelperClasses/RegistrationClass.cs b/src/Tools/Help/source/HelperClasses/RegistrationClass.cs new file mode 100644 index 0000000000..1aec24d1cf --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/RegistrationClass.cs @@ -0,0 +1,332 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Globalization; + using System.IO; + using System.Xml; + using MSHelpServices; + + public class Help2RegisterClass : IDisposable + { + HxRegisterSessionClass registerSession = null; + IHxRegister register = null; + IHxFilters filters = null; + IHxPlugIn plugins = null; + + #region Constructor/Destructor + public Help2RegisterClass() + { + try + { + registerSession = new HxRegisterSessionClass(); + registerSession.CreateTransaction(""); + + register = (IHxRegister)registerSession.GetRegistrationObject(HxRegisterSession_InterfaceType.HxRegisterSession_IHxRegister); + filters = (IHxFilters)registerSession.GetRegistrationObject(HxRegisterSession_InterfaceType.HxRegisterSession_IHxFilters); + plugins = (IHxPlugIn)registerSession.GetRegistrationObject(HxRegisterSession_InterfaceType.HxRegisterSession_IHxPlugIn); + } + catch (System.Runtime.InteropServices.COMException) + { + } + } + + ~Help2RegisterClass() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (registerSession != null) + { + // PLEASE DO NOT CHANGE OR REMOVE THAT!!! + + registerSession.CommitTransaction(); + + // It's very important to close the connection to the Help 2.0 + // environment. Trust me. I cannot explain because I don't know + // anything about the Help 2.0 API. I was experimenting with the + // Help 2.0 system and I knocked it out so many times ... + } + } + } + #endregion + + private static string GetXmlContent(string collectionFile, string xmlNode) + { + if (string.IsNullOrEmpty(collectionFile) || string.IsNullOrEmpty(xmlNode)) + { + return string.Empty; + } + try + { + XmlDocument xmldoc = new XmlDocument(); + xmldoc.Load(collectionFile); + XmlNodeList n = xmldoc.SelectNodes + (string.Format(CultureInfo.InvariantCulture, "/HelpCollection/{0}/@File", xmlNode)); + + if (n.Count > 0) + { + return n.Item(0).InnerText; + } + } + catch (NullReferenceException) + { + } + return string.Empty; + } + + #region Register/Unregister + public bool RegisterNamespace(string namespaceName, string collectionFile) + { + return this.RegisterNamespace(namespaceName, collectionFile, string.Empty, true); + } + + public bool RegisterNamespace(string namespaceName, string collectionFile, string description) + { + return this.RegisterNamespace(namespaceName, collectionFile, description, true); + } + + public bool RegisterNamespace(string namespaceName, string collectionFile, string description, bool overwrite) + { + if (register == null || string.IsNullOrEmpty(namespaceName) || string.IsNullOrEmpty(collectionFile)) + { + return false; + } + try + { + // The default setting is to remove the namespace. But if you + // just want to add some new help documents or filters, you + // shouldn't remove it. + if(overwrite && register.IsNamespace(namespaceName)) + { + register.RemoveNamespace(namespaceName); + } + + // If the namespace doesn't exist, create it + if(!register.IsNamespace(namespaceName)) + { + register.RegisterNamespace(namespaceName, collectionFile, description); + } + return true; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public bool RemoveNamespace(string namespaceName) + { + if (register == null || string.IsNullOrEmpty(namespaceName)) + { + return false; + } + try + { + if(register.IsNamespace(namespaceName)) + { + register.RemoveNamespace(namespaceName); + } + + return true; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public bool RegisterHelpFile(string namespaceName, string helpFileId, int languageId, string hxsFile, + string hxiFile, string hxqFile, string hxrFile, int hxsMediaId, + int hxqMediaId, int hxrMediaId, int sampleMediaId) + { + if (register == null || + string.IsNullOrEmpty(namespaceName) || + string.IsNullOrEmpty(helpFileId) || + string.IsNullOrEmpty(hxsFile)) + { + return false; + } + try + { + if(register.IsNamespace(namespaceName)) + { + register.RegisterHelpFileSet(namespaceName, // Help 2.0 Collection Namespace + helpFileId, // internal Help document ID + languageId, // Language ID + hxsFile, // Help document + hxiFile, // external Help index + hxqFile, // merged query file + hxrFile, // combined attributes file + hxsMediaId, + hxqMediaId, + hxrMediaId, + sampleMediaId); + + // If you want to know something about those file types, I suggest you + // take a look at Microsoft's VSHIK documentation. + } + + return true; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public bool RemoveHelpFile(string namespaceName, string helpFileId, int languageId) + { + if (register == null || + string.IsNullOrEmpty(namespaceName) || + string.IsNullOrEmpty(helpFileId)) + { + return false; + } + try + { + if(register.IsNamespace(namespaceName)) + { + register.RemoveHelpFile(namespaceName, helpFileId, languageId); + } + + return true; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public bool RegisterFilter(string namespaceName, string filterName, string filterQuery) + { + if (register == null || + filters == null || + string.IsNullOrEmpty(namespaceName) || + string.IsNullOrEmpty(filterName)) + { + return false; + } + try + { + filters.SetNamespace(namespaceName); + filters.SetCollectionFiltersFlag(true); + filters.RegisterFilter(filterName, filterQuery); + } + catch (System.Runtime.InteropServices.COMException) + { + } + + // This function ALWAYS returns true. It's because an empty filter + // query raises an exception but the filter will be created. A good + // example is the known "(no filter)" filter. + // So, don't change it. + + return true; + } + + public bool RemoveFilter(string namespaceName, string filterName) + { + if (register == null || + filters == null || + string.IsNullOrEmpty(namespaceName) || + string.IsNullOrEmpty(filterName)) + { + return false; + } + try + { + filters.SetNamespace(namespaceName); + filters.SetCollectionFiltersFlag(true); + filters.RemoveFilter(filterName); + + return true; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + + public bool RegisterPlugin(string parentNamespace, string childNamespace) + { + return this.PluginAction(parentNamespace, childNamespace, true); + } + + public bool RemovePlugin(string parentNamespace, string childNamespace) + { + return this.PluginAction(parentNamespace, childNamespace, false); + } + + private bool PluginAction(string parentNamespace, string childNamespace, bool registerIt) + { + if (register == null || + plugins == null || + string.IsNullOrEmpty(parentNamespace) || + string.IsNullOrEmpty(childNamespace) || + !register.IsNamespace(parentNamespace) || + !register.IsNamespace(childNamespace)) + { + return false; + } + + // if you want to remove a plug-in, at least it should be there + if(!registerIt && !PluginSearch.PluginDoesExist(parentNamespace, childNamespace)) + { + return false; + } + + try + { + // unregister plug-in + if(!registerIt) + { + if(PluginSearch.PluginDoesExist(parentNamespace, childNamespace)) + { + plugins.RemoveHelpPlugIn(parentNamespace, "", childNamespace, "", ""); + return true; + } + } + + // (re)register plug-in + string path1 = string.Empty; + + // The function requires the names of the TOC files. I can take them from + // the collection level files (*.HxC) of the collections. + string parentToc = GetXmlContent(register.GetCollection(parentNamespace), "TOCDef"); + string childToc = GetXmlContent(register.GetCollection(childNamespace), "TOCDef"); + string attr = GetXmlContent(register.GetCollection(childNamespace), "AttributeDef"); + + if(!string.IsNullOrEmpty(attr)) + { + path1 = Path.Combine(Path.GetDirectoryName(register.GetCollection(childNamespace)), attr); + } + + if(registerIt && !string.IsNullOrEmpty(parentToc) && !string.IsNullOrEmpty(childToc)) + { + plugins.RegisterHelpPlugIn(parentNamespace, parentToc, childNamespace, childToc, path1, 0); + return true; + } + else return false; + } + catch (System.Runtime.InteropServices.COMException) + { + } + return false; + } + #endregion + } +} diff --git a/src/Tools/Help/source/HelperClasses/ResourcesHelper.cs b/src/Tools/Help/source/HelperClasses/ResourcesHelper.cs new file mode 100644 index 0000000000..622229c1fb --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/ResourcesHelper.cs @@ -0,0 +1,27 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Reflection; + using System.Resources; + + public sealed class ResourcesHelper + { + static ResourcesHelper instance = new ResourcesHelper(); + + public static string GetString(string keyName) + { + return instance.StringResourceHelper.GetString(keyName); + } + + ResourceManager StringResourceHelper; + + ResourcesHelper() + { + StringResourceHelper = new ResourceManager("Help2Register.String", GetType().Assembly); + } + } +} diff --git a/src/Tools/Help/source/HelperClasses/XmlHelperClass.cs b/src/Tools/Help/source/HelperClasses/XmlHelperClass.cs new file mode 100644 index 0000000000..0368b7d9cc --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/XmlHelperClass.cs @@ -0,0 +1,121 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Xml; + using System.Xml.XPath; + + public sealed class XmlHelperClass + { + XmlHelperClass() + { + } + + public static bool SetXmlStringAttributeValue(XPathNavigator parentNode, string valueName, string newValue) + { + if (parentNode == null || string.IsNullOrEmpty(valueName)) + { + return false; + } + try + { + XPathNavigator factory = parentNode.Clone(); + do + { + factory.MoveToFirstAttribute(); + + if (string.Compare(factory.Name, valueName) == 0) + { + factory.SetValue(newValue); + return true; + } + } + while (!factory.MoveToNextAttribute()); + + parentNode.CreateAttribute(string.Empty, + valueName, + string.Empty, + newValue); + return true; + } + catch (ArgumentNullException) + { + } + catch (InvalidOperationException) + { + } + return false; + } + + public static string GetXmlStringValue(XPathNavigator parentNode, string valueName) + { + if (parentNode == null || string.IsNullOrEmpty(valueName)) + { + return string.Empty; + } + try + { + XPathNavigator node = parentNode.SelectSingleNode(valueName); + return node.Value; + } + catch (NullReferenceException) + { + } + return string.Empty; + } + + public static int GetXmlIntValue(XPathNavigator parentNode, string valueName, int defaultValue) + { + if (parentNode == null || string.IsNullOrEmpty(valueName)) + { + return defaultValue; + } + try + { + XPathNavigator node = parentNode.SelectSingleNode(valueName); + return node.ValueAsInt; + } + catch (NullReferenceException) + { + } + catch (FormatException) + { + } + return defaultValue; + } + + public static bool GetXmlBoolValue(XPathNavigator parentNode, string valueName) + { + return GetXmlBoolValue(parentNode, valueName, false); + } + + public static bool GetXmlBoolValue(XPathNavigator parentNode, string valueName, bool emptyIsTrue) + { + if (parentNode == null || string.IsNullOrEmpty(valueName)) + { + return false; + } + bool result = false; + + try + { + XPathNavigator node = parentNode.SelectSingleNode(valueName); + if (emptyIsTrue) + { + result = (node == null || (node != null && node.Value == "yes" && string.IsNullOrEmpty(node.Value))); + } + else + { + result = (node != null && node.Value == "yes"); + } + } + catch (NullReferenceException) + { + } + return result; + } + } +} diff --git a/src/Tools/Help/source/HelperClasses/XmlValidatorClass.cs b/src/Tools/Help/source/HelperClasses/XmlValidatorClass.cs new file mode 100644 index 0000000000..7093b034b6 --- /dev/null +++ b/src/Tools/Help/source/HelperClasses/XmlValidatorClass.cs @@ -0,0 +1,50 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.HelperClasses +{ + using System; + using System.Reflection; + using System.IO; + using System.Xml; + using System.Xml.Schema; + + public sealed class XmlValidator + { + private static bool validationSuccess = true; + private static bool beQuiet; + private static string me = + Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "register.xsd"); + + XmlValidator() + { + } + + public static bool XsdFileDoesExist + { + get { return File.Exists(me); } + } + + public static bool Validate(string xmlCommandFile, bool silentMode) + { + beQuiet = silentMode; + + XmlReaderSettings xsd = new XmlReaderSettings(); + xsd.Schemas.Add(ApplicationHelpers.Help2NamespaceUri, me); + xsd.ValidationType = ValidationType.Schema; + xsd.ValidationEventHandler += new ValidationEventHandler(ValidationCallback); + + XmlReader reader = XmlReader.Create(xmlCommandFile, xsd); + while(reader.Read()) { } + + return validationSuccess; + } + + private static void ValidationCallback(object sender, ValidationEventArgs e) + { + if(!beQuiet) Console.WriteLine(e.Message); + validationSuccess = false; + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/DocumentItemClass.cs b/src/Tools/Help/source/ItemClasses/DocumentItemClass.cs new file mode 100644 index 0000000000..2b54b2cad5 --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/DocumentItemClass.cs @@ -0,0 +1,102 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Globalization; + using System.Xml; + using System.Xml.XPath; + using HtmlHelp2Registration.HelperClasses; + + public class DocumentItemClass + { + private string id; + private string hxs; + private string hxi; + private string hxq; + private string hxr; + private int languageId; + private int hxsMediaId; + private int hxqMediaId; + private int hxrMediaId; + private int sampleMediaId; + + public DocumentItemClass(XPathNavigator rootFilenode) + { + if (rootFilenode == null) + { + throw new ArgumentNullException("rootFilenode"); + } + + this.id = XmlHelperClass.GetXmlStringValue(rootFilenode, "@Id"); + this.hxs = XmlHelperClass.GetXmlStringValue(rootFilenode, "@HxS"); + this.hxi = XmlHelperClass.GetXmlStringValue(rootFilenode, "@HxI"); + this.hxq = XmlHelperClass.GetXmlStringValue(rootFilenode, "@HxQ"); + this.hxr = XmlHelperClass.GetXmlStringValue(rootFilenode, "@HxR"); + this.languageId = XmlHelperClass.GetXmlIntValue(rootFilenode, "@LangId", 1033); + this.hxsMediaId = XmlHelperClass.GetXmlIntValue(rootFilenode, "@HxSMediaId", 0); + this.hxqMediaId = XmlHelperClass.GetXmlIntValue(rootFilenode, "@HxQMediaId", 0); + this.hxrMediaId = XmlHelperClass.GetXmlIntValue(rootFilenode, "@HxRMediaId", 0); + this.sampleMediaId = XmlHelperClass.GetXmlIntValue(rootFilenode, "@SampleMediaId", 0); + } + + #region Properties + public string Id + { + get { return this.id; } + } + + public string Hxs + { + get { return this.hxs; } + } + + public string Hxi + { + get{ return this.hxi; } + } + + public string Hxq + { + get { return this.hxq; } + } + + public string Hxr + { + get { return this.hxr; } + } + + public int LanguageId + { + get { return this.languageId; } + } + + public int HxsMediaId + { + get { return this.hxsMediaId; } + } + + public int HxqMediaId + { + get { return this.hxqMediaId; } + } + + public int HxrMediaId + { + get { return this.hxrMediaId; } + } + + public int SampleMediaId + { + get { return this.sampleMediaId; } + } + #endregion + + public override string ToString() + { + return String.Format(CultureInfo.InvariantCulture, "[Help 2.0 Document; {0}, {1}]", this.id, this.languageId); + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/FilterItemClass.cs b/src/Tools/Help/source/ItemClasses/FilterItemClass.cs new file mode 100644 index 0000000000..a592578c1c --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/FilterItemClass.cs @@ -0,0 +1,46 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Globalization; + using System.Xml; + using System.Xml.XPath; + using HtmlHelp2Registration.HelperClasses; + + public class FilterItemClass + { + private string name; + private string query; + + public FilterItemClass(XPathNavigator rootFilternode) + { + if (rootFilternode == null) + { + throw new ArgumentNullException("rootFilternode"); + } + + this.name = XmlHelperClass.GetXmlStringValue(rootFilternode, "@name"); + this.query = rootFilternode.Value; + } + + #region Properties + public string Name + { + get { return this.name; } + } + + public string Query + { + get { return this.query; } + } + #endregion + + public override string ToString() + { + return String.Format(CultureInfo.InvariantCulture, "[Help 2.0 Filter; {0} = {1}]", this.name, this.query); + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/ICommonItemClass.cs b/src/Tools/Help/source/ItemClasses/ICommonItemClass.cs new file mode 100644 index 0000000000..57d0b16d01 --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/ICommonItemClass.cs @@ -0,0 +1,12 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + public interface ICommonItemClass + { + void Register(); + void Unregister(); + } +} diff --git a/src/Tools/Help/source/ItemClasses/ItemEventHandling.cs b/src/Tools/Help/source/ItemClasses/ItemEventHandling.cs new file mode 100644 index 0000000000..091ceac694 --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/ItemEventHandling.cs @@ -0,0 +1,89 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + + public class CommonRegisterEventArgs : EventArgs + { + private readonly string name; + private readonly bool register = true; + + public CommonRegisterEventArgs(string name, bool register) + { + this.name = name; + this.register = register; + } + + public string Name + { + get { return this.name; } + } + + public bool Register + { + get { return this.register; } + } + } + + public class PluginRegisterEventArgs : EventArgs + { + private readonly string parent; + private readonly string child; + private readonly bool register = true; + + public PluginRegisterEventArgs(string parent, string child, bool register) + { + this.parent = parent; + this.child = child; + this.register = register; + } + + public string Parent + { + get { return this.parent; } + } + + public string Child + { + get { return this.child; } + } + + public bool Register + { + get { return this.register; } + } + } + + public class MergeNamespaceEventArgs : EventArgs + { + private readonly string name; + + public MergeNamespaceEventArgs(string name) + { + this.name = name; + } + + public string Name + { + get { return this.name; } + } + } + + public class LoggingEventArgs : EventArgs + { + private readonly string message; + + public LoggingEventArgs(string message) + { + this.message = message; + } + + public string Message + { + get { return this.message; } + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/NamespaceItemClass.cs b/src/Tools/Help/source/ItemClasses/NamespaceItemClass.cs new file mode 100644 index 0000000000..6dc5486623 --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/NamespaceItemClass.cs @@ -0,0 +1,152 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + using System.IO; + using System.Xml; + using System.Xml.XPath; + using System.Xml.Serialization; + using HtmlHelp2Registration.HelperClasses; + + public class NamespaceItemClass + { + private string name; + private string description; + private string collection; + private bool update; + private bool merge = true; + private bool noremove = true; + private List documents = new List(); + private List filters = new List(); + private List plugins = new List(); + private ReadOnlyCollection connections = null; + + public NamespaceItemClass(XPathNavigator rootNode) + { + if (rootNode == null) + { + throw new ArgumentNullException("rootNode"); + } + + this.name = XmlHelperClass.GetXmlStringValue(rootNode, "@name"); + this.description = XmlHelperClass.GetXmlStringValue(rootNode, "@description"); + this.collection = XmlHelperClass.GetXmlStringValue(rootNode, "@file"); + this.update = XmlHelperClass.GetXmlBoolValue(rootNode, "@update"); + this.merge = XmlHelperClass.GetXmlBoolValue(rootNode, "@merge", true); + this.noremove = XmlHelperClass.GetXmlBoolValue(rootNode, "@noremove"); + this.connections = PluginSearch.FindPluginAsGenericList(this.name); + + this.Initialize(rootNode); + } + + void Initialize(XPathNavigator rootNode) + { + // get all related documents + XPathNodeIterator files = + rootNode.SelectChildren("file", ApplicationHelpers.Help2NamespaceUri); + while (files.MoveNext()) + { + this.documents.Add(new DocumentItemClass(files.Current)); + } + + // get all related filters + XPathNodeIterator filters = + rootNode.SelectChildren("filter", ApplicationHelpers.Help2NamespaceUri); + while (filters.MoveNext()) + { + this.filters.Add(new FilterItemClass(filters.Current)); + } + + // get all related plugins + XPathNodeIterator p = + rootNode.SelectChildren("plugin", ApplicationHelpers.Help2NamespaceUri); + while (p.MoveNext()) + { + XPathNodeIterator child = + p.Current.SelectChildren("child", ApplicationHelpers.Help2NamespaceUri); + while (child.MoveNext()) + { + this.plugins.Add(new PluginChildItem(child.Current)); + } + } + } + + #region Properties + public string Name + { + get { return this.name; } + } + + public string Description + { + get { return this.description; } + } + + public string CollectionLevelFile + { + get { return this.collection; } + } + + public bool ForceCreation + { + get { return !this.update; } + } + + public bool Merge + { + get { return this.merge; } + } + + public bool Remove + { + get { return !this.noremove; } + } + + public ReadOnlyCollection Documents + { + get + { + ReadOnlyCollection roDocuments = + new ReadOnlyCollection(this.documents); + return roDocuments; + } + } + + public ReadOnlyCollection Filters + { + get + { + ReadOnlyCollection roFilters = + new ReadOnlyCollection(this.filters); + return roFilters; + } + } + + public ReadOnlyCollection Plugins + { + get + { + ReadOnlyCollection roPlugins = + new ReadOnlyCollection(this.plugins); + return roPlugins; + } + } + + public ReadOnlyCollection ConnectedNamespaces + { + get { return this.connections; } + } + #endregion + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[Help 2.0 Namespace; {0}, {1}]", this.name, this.description); + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/NamespacesItemClass.cs b/src/Tools/Help/source/ItemClasses/NamespacesItemClass.cs new file mode 100644 index 0000000000..0cb3a35988 --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/NamespacesItemClass.cs @@ -0,0 +1,285 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Xml; + using System.Xml.Serialization; + using HtmlHelp2Registration.HelperClasses; + + public class NamespacesItemClass : ICommonItemClass + { + private List helpNamespaces = new List(); + private XmlDocument xmldoc = new XmlDocument(); + private XmlNamespaceManager xmlns; + private string xmlFilename = string.Empty; + private string xmlXpathSequence = string.Empty; + + #region Constructor + public NamespacesItemClass(string xmlFilename) : this(xmlFilename, string.Empty) + { + } + + public NamespacesItemClass(string xmlFilename, string xmlXpathSequence) + { + this.xmlFilename = xmlFilename; + this.xmlXpathSequence = xmlXpathSequence; + this.Initialize(); + } + #endregion + + void Initialize() + { + this.xmlns = new XmlNamespaceManager(this.xmldoc.NameTable); + this.xmlns.AddNamespace("help2", ApplicationHelpers.Help2NamespaceUri); + + this.xmldoc.Load(this.xmlFilename); + XmlNodeList nodes = this.xmldoc.SelectNodes + (string.Format(CultureInfo.InvariantCulture, "/help2:register/help2:namespace{0}", this.xmlXpathSequence), this.xmlns); + + foreach (XmlNode node in nodes) + { + this.helpNamespaces.Add(new NamespaceItemClass(node.CreateNavigator())); + } + } + + public void Register() + { + foreach (NamespaceItemClass helpNamespace in helpNamespaces) + { + if (string.IsNullOrEmpty(helpNamespace.Name) || + string.IsNullOrEmpty(helpNamespace.CollectionLevelFile) || + !File.Exists(helpNamespace.CollectionLevelFile)) + { + continue; + } + + using (Help2RegisterClass register = new Help2RegisterClass()) + { + // force Help 2.0 namespace creation + if (helpNamespace.ForceCreation) + { + OnLogProgress(new LoggingEventArgs(helpNamespace.ToString())); + OnRegisterOrRemoveNamespace(new CommonRegisterEventArgs(helpNamespace.Name, true)); + register.RegisterNamespace(helpNamespace.Name, + helpNamespace.CollectionLevelFile, + helpNamespace.Description); + } + + // register Help 2.0 documents + foreach (DocumentItemClass document in helpNamespace.Documents) + { + if (string.IsNullOrEmpty(document.Id) || + string.IsNullOrEmpty(document.Hxs) || + !File.Exists(document.Hxs)) + { + continue; + } + + OnLogProgress(new LoggingEventArgs(document.ToString())); + OnRegisterOrRemoveHelpDocument(new CommonRegisterEventArgs(document.Id, true)); + register.RegisterHelpFile(helpNamespace.Name, + document.Id, + document.LanguageId, + document.Hxs, + document.Hxi, + document.Hxq, + document.Hxr, + document.HxsMediaId, + document.HxqMediaId, + document.HxrMediaId, + document.SampleMediaId); + } + + // register Help 2.0 filters + foreach (FilterItemClass filter in helpNamespace.Filters) + { + if (string.IsNullOrEmpty(filter.Name)) + { + continue; + } + + OnLogProgress(new LoggingEventArgs(filter.ToString())); + OnRegisterOrRemoveFilter(new CommonRegisterEventArgs(filter.Name, true)); + register.RegisterFilter(helpNamespace.Name, filter.Name, filter.Query); + } + + // register Help 2.0 child plug-ins + foreach (PluginChildItem plugin in helpNamespace.Plugins) + { + if (string.IsNullOrEmpty(plugin.MatchingName)) + { + continue; + } + + OnLogProgress(new LoggingEventArgs(plugin.ToString())); + OnRegisterOrRemovePlugin(new PluginRegisterEventArgs(helpNamespace.Name, plugin.MatchingName, true)); + register.RegisterPlugin(helpNamespace.Name, plugin.MatchingName); + + if (string.Compare(plugin.Name, plugin.MatchingName) != 0) + { + this.PatchXmlNode(helpNamespace.Name, plugin.Name, plugin.MatchingName); + } + } + + // merge Help 2.0 namespace + if (helpNamespace.Merge) + { + OnLogProgress(new LoggingEventArgs(string.Format(CultureInfo.InvariantCulture, "[merging {0}]", helpNamespace.Name))); + OnNamespaceMerge(new MergeNamespaceEventArgs(helpNamespace.Name)); + MergeNamespace.CallMerge(helpNamespace.Name); + + foreach(string connectedNamespace in helpNamespace.ConnectedNamespaces) + { + OnLogProgress(new LoggingEventArgs(string.Format(CultureInfo.InvariantCulture, "[merging {0}]", connectedNamespace))); + OnNamespaceMerge(new MergeNamespaceEventArgs(connectedNamespace)); + MergeNamespace.CallMerge(connectedNamespace); + } + } + } + } + } + + public void Unregister() + { + foreach (NamespaceItemClass helpNamespace in helpNamespaces) + { + if (string.IsNullOrEmpty(helpNamespace.Name)) + { + continue; + } + + using (Help2RegisterClass register = new Help2RegisterClass()) + { + // remove this Help 2.0 namespace, if it is a plug-in + foreach (string connectedNamespace in helpNamespace.ConnectedNamespaces) + { + OnRegisterOrRemovePlugin(new PluginRegisterEventArgs(connectedNamespace, helpNamespace.Name, false)); + register.RemovePlugin(connectedNamespace, helpNamespace.Name); + + OnNamespaceMerge(new MergeNamespaceEventArgs(connectedNamespace)); + MergeNamespace.CallMerge(connectedNamespace); + } + + // remove this namespace's child plug-ins + foreach (PluginChildItem plugin in helpNamespace.Plugins) + { + OnLogProgress(new LoggingEventArgs(plugin.ToString())); + OnRegisterOrRemovePlugin(new PluginRegisterEventArgs(helpNamespace.Name, plugin.MatchingName, false)); + register.RemovePlugin(helpNamespace.Name, plugin.MatchingName); + } + + // remove this namespace's filters + foreach (FilterItemClass filter in helpNamespace.Filters) + { + OnLogProgress(new LoggingEventArgs(filter.ToString())); + OnRegisterOrRemoveFilter(new CommonRegisterEventArgs(filter.Name, false)); + register.RemoveFilter(helpNamespace.Name, filter.Name); + } + + // remove this namespace's documents + foreach (DocumentItemClass document in helpNamespace.Documents) + { + OnLogProgress(new LoggingEventArgs(document.ToString())); + OnRegisterOrRemoveHelpDocument(new CommonRegisterEventArgs(document.Id, false)); + register.RemoveHelpFile(helpNamespace.Name, document.Id, document.LanguageId); + } + + // remove this namespace, ... + if (helpNamespace.Remove) + { + OnRegisterOrRemoveNamespace(new CommonRegisterEventArgs(helpNamespace.Name, false)); + register.RemoveNamespace(helpNamespace.Name); + } + // ... or just (re)merge it + else + { + OnNamespaceMerge(new MergeNamespaceEventArgs(helpNamespace.Name)); + MergeNamespace.CallMerge(helpNamespace.Name); + } + } + } + } + + void PatchXmlNode(string namespaceName, string pluginName, string matchingName) + { + if (this.xmldoc == null || + string.IsNullOrEmpty(namespaceName) || + string.IsNullOrEmpty(pluginName) || + string.IsNullOrEmpty(matchingName)) + { + return; + } + + XmlNode node = xmldoc.SelectSingleNode + (string.Format(CultureInfo.InvariantCulture, + "/help2:register/help2:namespace[@name=\"{0}\"]/help2:plugin/help2:child[@name=\"{1}\"]", + namespaceName, pluginName), this.xmlns); + XmlHelperClass.SetXmlStringAttributeValue(node.CreateNavigator(), "name", matchingName); + xmldoc.Save(this.xmlFilename); + } + + #region Events + public event EventHandler RegisterOrRemoveNamespace; + public event EventHandler RegisterOrRemoveHelpDocument; + public event EventHandler RegisterOrRemoveFilter; + public event EventHandler RegisterOrRemovePlugin; + public event EventHandler NamespaceMerge; + public event EventHandler LogProgress; + + private void OnRegisterOrRemoveNamespace(CommonRegisterEventArgs e) + { + if (RegisterOrRemoveNamespace != null) + { + RegisterOrRemoveNamespace(null, e); + } + } + + private void OnRegisterOrRemoveHelpDocument(CommonRegisterEventArgs e) + { + if (RegisterOrRemoveHelpDocument != null) + { + RegisterOrRemoveHelpDocument(null, e); + } + } + + private void OnRegisterOrRemoveFilter(CommonRegisterEventArgs e) + { + if (RegisterOrRemoveFilter != null) + { + RegisterOrRemoveFilter(null, e); + } + } + + private void OnRegisterOrRemovePlugin(PluginRegisterEventArgs e) + { + if (RegisterOrRemovePlugin != null) + { + RegisterOrRemovePlugin(null, e); + } + } + + private void OnNamespaceMerge(MergeNamespaceEventArgs e) + { + if (NamespaceMerge != null) + { + NamespaceMerge(null, e); + } + } + + private void OnLogProgress(LoggingEventArgs e) + { + if (LogProgress != null) + { + LogProgress(null, e); + } + } + #endregion + } +} diff --git a/src/Tools/Help/source/ItemClasses/PluginItemClass.cs b/src/Tools/Help/source/ItemClasses/PluginItemClass.cs new file mode 100644 index 0000000000..2e777c216d --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/PluginItemClass.cs @@ -0,0 +1,115 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Globalization; + using System.Collections.Generic; + using System.Xml; + using System.Xml.XPath; + using HtmlHelp2Registration.HelperClasses; + + public class PluginParentItem + { + private string realName; + private string matchingName; + private bool merge; + private List children = new List(); + + public PluginParentItem(XPathNavigator pluginRootnode) + { + if (pluginRootnode == null) + { + throw new ArgumentNullException("pluginRootnode"); + } + this.realName = XmlHelperClass.GetXmlStringValue(pluginRootnode, "@parent"); + this.matchingName = PluginSearch.GetFirstMatchingNamespaceName(this.realName); + this.merge = XmlHelperClass.GetXmlBoolValue(pluginRootnode, "@merge", true); + string childName = XmlHelperClass.GetXmlStringValue(pluginRootnode, "@child"); + + if (!string.IsNullOrEmpty(childName)) + { + this.children.Add(new PluginChildItem(childName)); + } + else + { + XPathNodeIterator pChild = + pluginRootnode.SelectChildren("child", ApplicationHelpers.Help2NamespaceUri); + while (pChild.MoveNext()) + { + this.children.Add(new PluginChildItem(pChild.Current)); + } + } + } + + #region Properties + public string Name + { + get { return this.realName; } + } + + public string MatchingName + { + get { return this.matchingName; } + } + + public bool Merge + { + get { return this.merge; } + } + #endregion + + public System.Collections.IEnumerator GetEnumerator() + { + foreach (PluginChildItem child in this.children) + { + yield return child; + } + } + } + + public class PluginChildItem + { + private string realName; + private string matchingName; + + public PluginChildItem(XPathNavigator pluginRootnode) + { + if (pluginRootnode == null) + { + throw new ArgumentNullException("pluginRootnode"); + } + this.realName = XmlHelperClass.GetXmlStringValue(pluginRootnode, "@name"); + this.matchingName = PluginSearch.GetFirstMatchingNamespaceName(this.realName); + } + + public PluginChildItem(string childName) + { + if (string.IsNullOrEmpty(childName)) + { + throw new ArgumentNullException("childName"); + } + this.realName = childName; + this.matchingName = PluginSearch.GetFirstMatchingNamespaceName(this.realName); + } + + #region Properties + public string Name + { + get { return this.realName; } + } + + public string MatchingName + { + get { return this.matchingName; } + } + #endregion + + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "[Help 2.0 Plug-in; {0}]", this.matchingName); + } + } +} diff --git a/src/Tools/Help/source/ItemClasses/PluginsItemClass.cs b/src/Tools/Help/source/ItemClasses/PluginsItemClass.cs new file mode 100644 index 0000000000..6709b6ed1b --- /dev/null +++ b/src/Tools/Help/source/ItemClasses/PluginsItemClass.cs @@ -0,0 +1,186 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration.ItemClasses +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Xml; + using System.Xml.XPath; + using HtmlHelp2Registration.HelperClasses; + + public class PluginsItemClass : ICommonItemClass + { + private List plugins = new List(); + private XmlDocument xmldoc = new XmlDocument(); + private XmlNamespaceManager xmlns; + private string xmlFilename = string.Empty; + private string xmlXpathSequence = string.Empty; + + #region Constructor + public PluginsItemClass(string xmlFilename) : this(xmlFilename, string.Empty) + { + } + + public PluginsItemClass(string xmlFilename, string xmlXpathSequence) + { + this.xmlFilename = xmlFilename; + this.xmlXpathSequence = xmlXpathSequence; + this.Initialize(); + } + #endregion + + void Initialize() + { + this.xmlns = new XmlNamespaceManager(this.xmldoc.NameTable); + this.xmlns.AddNamespace("help2", ApplicationHelpers.Help2NamespaceUri); + + this.xmldoc.Load(this.xmlFilename); + XmlNodeList nodes = this.xmldoc.SelectNodes + (string.Format(CultureInfo.InvariantCulture, "/help2:register/help2:plugin{0}", this.xmlXpathSequence), this.xmlns); + + foreach (XmlNode node in nodes) + { + this.plugins.Add(new PluginParentItem(node.CreateNavigator())); + } + } + + public void Register() + { + foreach (PluginParentItem plugin in this.plugins) + { + if (string.IsNullOrEmpty(plugin.MatchingName)) + { + continue; + } + + using (Help2RegisterClass register = new Help2RegisterClass()) + { + foreach (PluginChildItem child in plugin) + { + if (string.IsNullOrEmpty(child.MatchingName)) + { + continue; + } + + OnRegisterOrRemovePlugin(new PluginRegisterEventArgs(plugin.MatchingName, child.MatchingName, true)); + register.RegisterPlugin(plugin.MatchingName, child.MatchingName); + + if (string.Compare(plugin.Name, plugin.MatchingName) != 0) + { + this.PatchParentXmlNode(plugin.Name, plugin.MatchingName); + } + if (string.Compare(child.Name, child.MatchingName) != 0) + { + this.PatchChildXmlNode(plugin.Name, child.Name, child.MatchingName); + } + } + + if (plugin.Merge) + { + OnNamespaceMerge(new MergeNamespaceEventArgs(plugin.MatchingName)); + MergeNamespace.CallMerge(plugin.MatchingName); + } + } + } + } + + public void Unregister() + { + foreach (PluginParentItem plugin in this.plugins) + { + if (string.IsNullOrEmpty(plugin.MatchingName)) + { + continue; + } + + using (Help2RegisterClass register = new Help2RegisterClass()) + { + foreach (PluginChildItem child in plugin) + { + if (string.IsNullOrEmpty(child.MatchingName)) + { + continue; + } + + OnRegisterOrRemovePlugin(new PluginRegisterEventArgs(plugin.MatchingName, child.MatchingName, false)); + register.RemovePlugin(plugin.MatchingName, child.MatchingName); + } + + if (plugin.Merge) + { + OnNamespaceMerge(new MergeNamespaceEventArgs(plugin.MatchingName)); + MergeNamespace.CallMerge(plugin.MatchingName); + } + } + } + } + + private void PatchParentXmlNode(string realParentName, string matchingParentName) + { + if (this.xmldoc == null || + string.IsNullOrEmpty(realParentName) || + string.IsNullOrEmpty(matchingParentName)) + { + return; + } + + XmlNode node = this.xmldoc.SelectSingleNode + (string.Format(CultureInfo.InvariantCulture, "/register/plugin[@parent=\"{0}\"]", realParentName)); + XmlHelperClass.SetXmlStringAttributeValue(node.CreateNavigator(), "parent", matchingParentName); + this.xmldoc.Save(this.xmlFilename); + } + + private void PatchChildXmlNode(string realParentName, string realChildName, string matchingChildName) + { + if (this.xmldoc == null || + string.IsNullOrEmpty(realParentName) || + string.IsNullOrEmpty(realChildName) || + string.IsNullOrEmpty(matchingChildName)) + { + return; + } + + XmlNode node = this.xmldoc.SelectSingleNode + (string.Format(CultureInfo.InvariantCulture, "/register/plugin[@parent=\"{0}\"]", realParentName)); + if(node != null) + { + string childName = XmlHelperClass.GetXmlStringValue(node.CreateNavigator(), "@child"); + if(childName.Length > 0 && String.Compare(childName, realChildName) == 0) + { + XmlHelperClass.SetXmlStringAttributeValue(node.CreateNavigator(), "child", matchingChildName); + } + else + { + XmlNode child = node.SelectSingleNode(string.Format(CultureInfo.InvariantCulture, "child[@name=\"{0}\"]", realChildName)); + XmlHelperClass.SetXmlStringAttributeValue(child.CreateNavigator(), "name", matchingChildName); + } + this.xmldoc.Save(this.xmlFilename); + } + } + + #region Events + public event EventHandler RegisterOrRemovePlugin; + public event EventHandler NamespaceMerge; + + private void OnRegisterOrRemovePlugin(PluginRegisterEventArgs e) + { + if (RegisterOrRemovePlugin != null) + { + RegisterOrRemovePlugin(null, e); + } + } + + private void OnNamespaceMerge(MergeNamespaceEventArgs e) + { + if (NamespaceMerge != null) + { + NamespaceMerge(null, e); + } + } + #endregion + } +} diff --git a/src/Tools/Help/source/MSHelpServices.dll b/src/Tools/Help/source/MSHelpServices.dll new file mode 100644 index 0000000000..aa890731f4 Binary files /dev/null and b/src/Tools/Help/source/MSHelpServices.dll differ diff --git a/src/Tools/Help/source/String.resources b/src/Tools/Help/source/String.resources new file mode 100644 index 0000000000..afb3dad6ca Binary files /dev/null and b/src/Tools/Help/source/String.resources differ diff --git a/src/Tools/Help/source/register.cs b/src/Tools/Help/source/register.cs new file mode 100644 index 0000000000..3ef5488152 --- /dev/null +++ b/src/Tools/Help/source/register.cs @@ -0,0 +1,254 @@ +// +// Help 2.0 Registration Utility +// Copyright (c) 2005 Mathias Simmack. All rights reserved. +// +namespace HtmlHelp2Registration +{ + using System; + using System.Collections.Specialized; + using System.Globalization; + using System.IO; + using System.Reflection; + using HtmlHelp2Registration.HelperClasses; + using HtmlHelp2Registration.ItemClasses; + + class HtmlHelp2RegistrationTool + { + #region [STAThread] + [STAThread] + public static int Main(string[] args) + { + HtmlHelp2RegistrationTool register = new HtmlHelp2RegistrationTool(); + return register.Run(args); + } + #endregion + + private bool showLogo = true; + private bool showHelp; + private bool beQuiet; + private bool errorCodes; + private string actionParam = string.Empty; + private string xmlFilename = string.Empty; + private string xpathSequence = string.Empty; + private string[] invalidProcesses = new string[] { "dexplore.exe", "sharpdevelop.exe" }; + + public int Run(string[] args) + { + this.ParseCommandLine(args); + + if (this.showLogo) + { + Assembly me = Assembly.GetExecutingAssembly(); + Console.WriteLine("Help 2.0 Registration Utility v{0}", me.GetName().Version.ToString()); + Console.WriteLine("Copyright (c) 2005 Mathias Simmack. All rights reserved."); + Console.WriteLine(); + } + + if (this.showHelp || args.Length == 0) + { + Assembly me = Assembly.GetExecutingAssembly(); + Console.WriteLine(ResourcesHelper.GetString("RegisterToolCommandLineOptions"), + me.GetName().Name); + + return (this.errorCodes)?1:0; + } + + // Error code 2 is obsolete. It was set in my Delphi version if XML was not installed + + if (!ApplicationHelpers.IsClassRegistered("{31411198-A502-11D2-BBCA-00C04F8EC294}")) + { + if(!this.beQuiet) Console.WriteLine(ResourcesHelper.GetString("ErrorNoHelp2Environment")); + return (this.errorCodes)?3:0; + } + + if (!ApplicationHelpers.IsThisUserPrivileged()) + { + if(!this.beQuiet) Console.WriteLine(ResourcesHelper.GetString("ErrorInvalidPrivileges")); + return (this.errorCodes)?4:0; + } + + if (this.actionParam != "/r" && this.actionParam != "/u" && this.actionParam != "+r" && + this.actionParam != "-r" && this.actionParam != "+p" && this.actionParam != "-p") + { + if(!this.beQuiet) Console.WriteLine(ResourcesHelper.GetString("ErrorInvalidCommandLine"), + this.actionParam); + return (this.errorCodes)?5:0; + } + + if (string.IsNullOrEmpty(this.xmlFilename) || !File.Exists(this.xmlFilename)) + { + if(!this.beQuiet) Console.WriteLine(ResourcesHelper.GetString("ErrorInvalidXmlFile"), + this.xmlFilename); + return (this.errorCodes)?6:0; + } + + if (!XmlValidator.XsdFileDoesExist) + { + if(!this.beQuiet) Console.WriteLine(ResourcesHelper.GetString("ErrorCannotValidateXmlFile"), + this.xmlFilename); + return (this.errorCodes)?7:0; + } + if (!XmlValidator.Validate(this.xmlFilename, this.beQuiet)) + { + // get a message from the validator class + return (this.errorCodes)?7:0; + } + + ApplicationHelpers.KillIllegalProcesses(this.invalidProcesses); + + if (this.actionParam == "/r" || this.actionParam == "+r") this.DoHelpStuff(true); + if (this.actionParam == "/r" || this.actionParam == "+p") this.DoPluginStuff(true); + if (this.actionParam == "/u" || this.actionParam == "-p") this.DoPluginStuff(false); + if (this.actionParam == "/u" || this.actionParam == "-r") this.DoHelpStuff(false); + + return 0; + } + + private void ParseCommandLine(string[] args) + { + if (args.Length == 0) + { + return; + } + + this.actionParam = args[0].ToLower(CultureInfo.InvariantCulture); + this.xmlFilename = args[args.Length - 1]; + + for (int i = 1; i < args.Length - 1; i++) + { + string arg = args[i]; + + if (string.IsNullOrEmpty(arg)) + { + continue; + } + + if ('-' == arg[0] || '/' == arg[0]) + { + string parameter = arg.Substring(1); + + if ("nologo" == parameter) + { + this.showLogo = false; + } + if ("?" == parameter || "help" == parameter) + { + this.showHelp = true; + } + if ("quiet" == parameter || "q" == parameter) + { + this.beQuiet = true; + } + if (parameter.StartsWith("xpath:")) + { + this.xpathSequence = parameter.Substring(6); + } + if ("useerrorcodes" == parameter) + { + this.errorCodes = true; + } + } + } + } + + #region Action + private void DoHelpStuff(bool register) + { + NamespacesItemClass namespaces = + new NamespacesItemClass(this.xmlFilename, this.xpathSequence); + + if (!this.beQuiet) + { + namespaces.RegisterOrRemoveNamespace += this.RegisterOrRemoveNamespace; + namespaces.RegisterOrRemoveHelpDocument += this.RegisterOrRemoveHelpDocument; + namespaces.RegisterOrRemoveFilter += this.RegisterOrRemoveFilter; + namespaces.RegisterOrRemovePlugin += this.RegisterOrRemovePlugin; + namespaces.NamespaceMerge += this.NamespaceMerge; + } + if (register) + { + namespaces.Register(); + } + else + { + namespaces.Unregister(); + } + } + + private void DoPluginStuff(bool register) + { + PluginsItemClass plugins = + new PluginsItemClass(this.xmlFilename, this.xpathSequence); + + if (!this.beQuiet) + { + plugins.RegisterOrRemovePlugin += this.RegisterOrRemovePlugin; + plugins.NamespaceMerge += this.NamespaceMerge; + } + if (register) + { + plugins.Register(); + } + else + { + plugins.Unregister(); + } + } + #endregion + + #region Events + private void RegisterOrRemoveNamespace(object sender, CommonRegisterEventArgs e) + { + if (e.Register) + { + Console.WriteLine(ResourcesHelper.GetString("RegisterHelpNamespace"), e.Name); + } + else + { + Console.WriteLine(ResourcesHelper.GetString("RemoveHelpNamespace"), e.Name); + } + } + + private void RegisterOrRemoveHelpDocument(object sender, CommonRegisterEventArgs e) + { + if (e.Register) + { + Console.WriteLine(ResourcesHelper.GetString("RegisterHelpDocument"), e.Name); + } + else + { + Console.WriteLine(ResourcesHelper.GetString("RemoveHelpDocument"), e.Name); + } + } + + private void RegisterOrRemoveFilter(object sender, CommonRegisterEventArgs e) + { + if (e.Register) + { + Console.WriteLine(ResourcesHelper.GetString("RegisterHelpFilter"), e.Name); + } + else + { + Console.WriteLine(ResourcesHelper.GetString("RemoveHelpFilter"), e.Name); + } + } + + private void RegisterOrRemovePlugin(object sender, PluginRegisterEventArgs e) + { + if (e.Register) + { + Console.WriteLine(ResourcesHelper.GetString("RegisterHelpPlugin"), e.Child, e.Parent); + } + else + { + Console.WriteLine(ResourcesHelper.GetString("RemoveHelpPlugin"), e.Child, e.Parent); + } + } + + private void NamespaceMerge(object sender, MergeNamespaceEventArgs e) + { + Console.WriteLine(ResourcesHelper.GetString("MergeHelpNamespace"), e.Name); + } + #endregion + } +}