diff --git a/src/AddIns/Misc/HelpViewer/Configuration/AssemblyInfo.cs b/src/AddIns/Misc/HelpViewer/Configuration/AssemblyInfo.cs new file mode 100644 index 0000000000..5982ec6dc3 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Configuration/AssemblyInfo.cs @@ -0,0 +1,16 @@ +using System.Reflection; +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("Microsoft Help Viewer")] +[assembly: AssemblyDescription("Microsoft Help System v1.0 for SharpDevelop")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: System.CLSCompliant(false)] diff --git a/src/AddIns/Misc/HelpViewer/HelpViewer.addin b/src/AddIns/Misc/HelpViewer/HelpViewer.addin new file mode 100644 index 0000000000..d8f3bbacf3 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/HelpViewer.addin @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/HelpViewer/HelpViewer.csproj b/src/AddIns/Misc/HelpViewer/HelpViewer.csproj new file mode 100644 index 0000000000..98523e3a7b --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/HelpViewer.csproj @@ -0,0 +1,105 @@ + + + + {80F76D10-0B44-4D55-B4BD-DAEB5464090C} + Debug + x86 + Library + MSHelpSystem + HelpViewer + v4.0 + False + False + 4 + false + OnBuildSuccess + + + x86 + False + Auto + 4194304 + 4096 + + + ..\..\..\..\AddIns\AddIns\Misc\HelpViewer\ + true + Full + False + True + DEBUG;TRACE + + + ..\..\..\..\AddIns\AddIns\Misc\HelpViewer\ + false + None + True + False + TRACE + + + + ..\..\..\..\bin\ICSharpCode.Core.dll + False + + + ..\..\..\..\bin\ICSharpCode.Core.Presentation.dll + False + + + ..\..\..\..\bin\ICSharpCode.SharpDevelop.dll + False + + + + + + + 3.5 + + + + + + + 3.5 + + + + + + Always + + + + + Configuration\GlobalAssemblyInfo.cs + + + + + + + + + + Help3OptionsPanel.xaml + Code + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/HelpViewer.sln b/src/AddIns/Misc/HelpViewer/HelpViewer.sln new file mode 100644 index 0000000000..43cffb0f03 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/HelpViewer.sln @@ -0,0 +1,17 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +# SharpDevelop 4.0.0.5828 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelpViewer", "HelpViewer.csproj", "{80F76D10-0B44-4D55-B4BD-DAEB5464090C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {80F76D10-0B44-4D55-B4BD-DAEB5464090C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80F76D10-0B44-4D55-B4BD-DAEB5464090C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80F76D10-0B44-4D55-B4BD-DAEB5464090C}.Release|Any CPU.Build.0 = Release|Any CPU + {80F76D10-0B44-4D55-B4BD-DAEB5464090C}.Release|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/AddIns/Misc/HelpViewer/Source/BrowserScheme.cs b/src/AddIns/Misc/HelpViewer/Source/BrowserScheme.cs new file mode 100644 index 0000000000..f8c0142bd8 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/BrowserScheme.cs @@ -0,0 +1,29 @@ +using System; +using System.Globalization; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.BrowserDisplayBinding; +using MSHelpSystem.Core; + +namespace MSHelpSystem +{ + public class BrowserScheme : DefaultSchemeExtension + { + public override void GoHome(HtmlViewPane pane) + { + if (pane == null) { + throw new ArgumentNullException("pane"); + } + LoggingService.Info("Help 3.0: Calling browser (\"GoHome()\")"); + DisplayHelp.Catalog(); + } + + public override void GoSearch(HtmlViewPane pane) + { + if (pane == null) { + throw new ArgumentNullException("pane"); + } + LoggingService.Info("Help 3.0: Calling browser (\"GoSearch()\")"); + pane.Navigate(new Uri(string.Format(@"http://social.msdn.microsoft.com/Search/{0}", CultureInfo.CurrentCulture.Name.ToLower()))); + } + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/DisplayHelp.cs b/src/AddIns/Misc/HelpViewer/Source/Core/DisplayHelp.cs new file mode 100644 index 0000000000..3385ca8f1e --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/DisplayHelp.cs @@ -0,0 +1,193 @@ +using System; +using System.Globalization; +using System.Threading; +using System.Windows.Forms; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.BrowserDisplayBinding; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Project; +using MSHelpSystem.Helper; +using MSHelpSystem.Core.Native; + +namespace MSHelpSystem.Core +{ + internal sealed class DisplayHelp + { + DisplayHelp() + { + } + + public static void Catalog() + { + if (!Help3Environment.IsLocalHelp) { + MessageBox.Show("You requested an offline feature in the online help mode. You have to change the mode in order to use this feature.", + "Help Viewer", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + Help3Catalog c = Help3Service.ActiveCatalog; + if (c == null) { + throw new ArgumentNullException("c"); + } + string helpCatalogUrl = string.Format(@"ms-xhelp://?method=page&id=-1&product={0}&productVersion={1}&locale={2}", c.ProductCode, c.ProductVersion, c.Locale); + LoggingService.Debug(string.Format("Help 3.0: {0}", helpCatalogUrl)); + DisplayLocalHelp(helpCatalogUrl); + } + + public static void Page(string pageId) + { + if (string.IsNullOrEmpty(pageId)) { + throw new ArgumentNullException("pageId"); + } + if (!Help3Environment.IsLocalHelp) { + MessageBox.Show("You requested an offline feature in the online help mode. You have to change the mode in order to use this feature.", + "Help Viewer", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + Help3Catalog c = Help3Service.ActiveCatalog; + if (c == null) { + throw new ArgumentNullException("c"); + } + string helpPageUrl = string.Format(@"ms-xhelp://?method=page&id={3}&product={0}&productVersion={1}&locale={2}", c.ProductCode, c.ProductVersion, c.Locale, pageId); + LoggingService.Debug(string.Format("Help 3.0: {0}", helpPageUrl)); + DisplayLocalHelp(helpPageUrl); + } + + public static void ContextualHelp(string contextual) + { + if (string.IsNullOrEmpty(contextual)) { + throw new ArgumentNullException("contextual"); + } + if (!Help3Environment.IsLocalHelp) { + DisplayHelpOnMSDN(contextual); + return; + } + Help3Catalog c = Help3Service.ActiveCatalog; + if (c == null) { + throw new ArgumentNullException("c"); + } + string helpContextualUrl = string.Format(@"ms-xhelp://?method=f1&query={3}&product={0}&productVersion={1}&locale={2}", c.ProductCode, c.ProductVersion, c.Locale, contextual); + LoggingService.Debug(string.Format("Help 3.0: {0}", helpContextualUrl)); + DisplayLocalHelp(helpContextualUrl); + } + + public static void Search(string searchWords) + { + if (string.IsNullOrEmpty(searchWords)) { + throw new ArgumentNullException("searchWords"); + } + if (!Help3Environment.IsLocalHelp) { + DisplaySearchOnMSDN(searchWords); + return; + } + Help3Catalog c = Help3Service.ActiveCatalog; + if (c == null) { + throw new ArgumentNullException("c"); + } + string helpSearchUrl = string.Format(@"ms-xhelp://method=search&query={3}&product={0}&productVersion={1}&locale={2}", c.ProductCode, c.ProductVersion, c.Locale, searchWords.Replace(" ", "+")); + LoggingService.Debug(string.Format("Help 3.0: {0}", helpSearchUrl)); + DisplayLocalHelp(helpSearchUrl); + } + + public static void Keywords(string keywords) + { + if (string.IsNullOrEmpty(keywords)) { + throw new ArgumentNullException("keywords"); + } + if (!Help3Environment.IsLocalHelp) { + MessageBox.Show("You requested an offline feature in the online help mode. You have to change the mode in order to use this feature.", + "Help Viewer", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + Help3Catalog c = Help3Service.ActiveCatalog; + if (c == null) { + throw new ArgumentNullException("c"); + } + string helpKeywordsUrl = string.Format(@"ms-xhelp://?method=keywords&query={3}&product={0}&productVersion={1}&locale={2}", c.ProductCode, c.ProductVersion, c.Locale, keywords); + LoggingService.Debug(string.Format("Help 3.0: {0}", helpKeywordsUrl)); + DisplayLocalHelp(helpKeywordsUrl); + } + + + static string FormatMsXHelpToHttp(string helpUrl) + { + string output = helpUrl; + if (output.StartsWith("ms-xhelp://?")) { + output = string.Format( + @"http://127.0.0.1:{0}/help/{1}-{2}/ms.help?{3}", + HelpLibraryAgent.PortNumber, + NativeMethods.GetSessionId(), + HelpLibraryAgent.ProcessId, + output.Replace("ms-xhelp://?", "")); + } + return output; + } + + static void DisplayLocalHelp(string arguments) + { + // TODO: set "embedded" to TRUE if we have a TOC control or something similar + DisplayLocalHelp(arguments, false); + } + + static void DisplayLocalHelp(string arguments, bool embedded) + { + if (!Help3Environment.IsLocalHelp) { return; } + if (!HelpLibraryAgent.IsRunning) { + HelpLibraryAgent.Start(); + Thread.Sleep(0x3e8); + } + string helpUrl = string.Format(@"{0}{1}{2}", FormatMsXHelpToHttp(arguments), ProjectLanguages.FormattedAsHttpParam(), (embedded)?"&embedded=true":string.Empty); + BrowserPane browser = ActiveHelp3Browser(); + if (browser != null) { + LoggingService.Info(string.Format("Help 3.0: Navigating to {0}", helpUrl)); + browser.Navigate(helpUrl); + browser.WorkbenchWindow.SelectWindow(); + } + } + + static void DisplayHelpOnMSDN(string keyword) + { + string msdnUrl = string.Format(@"http://msdn.microsoft.com/library/{0}.aspx", keyword); + BrowserPane browser = ActiveHelp3Browser(); + if (browser != null) { + LoggingService.Info(string.Format("Help 3.0: Navigating to {0}", msdnUrl)); + browser.Navigate(msdnUrl); + browser.WorkbenchWindow.SelectWindow(); + } + } + + static void DisplaySearchOnMSDN(string searchWords) + { + string msdnUrl = string.Format(@"http://social.social.msdn.microsoft.com/Search/{0}/?query={1}&ac=3", CultureInfo.CurrentUICulture.ToString(), searchWords.Replace(" ", "+")); + BrowserPane browser = ActiveHelp3Browser(); + if (browser != null) { + LoggingService.Info(string.Format("Help 3.0: Navigating to {0}", msdnUrl)); + browser.Navigate(msdnUrl); + browser.WorkbenchWindow.SelectWindow(); + } + } + + static BrowserPane ActiveHelp3Browser() + { + IWorkbenchWindow window = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow; + if (window != null) + { + BrowserPane browser = window.ActiveViewContent as BrowserPane; + if (browser != null && browser.Url.Scheme == "http") return browser; + } + foreach (IViewContent view in WorkbenchSingleton.Workbench.ViewContentCollection) + { + BrowserPane browser = view as BrowserPane; + if (browser != null && browser.Url.Scheme == "http") return browser; + } + BrowserPane tmp = new BrowserPane(); + WorkbenchSingleton.Workbench.ShowView(tmp); + return tmp; + } + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/Help3Catalog.cs b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Catalog.cs new file mode 100644 index 0000000000..cb5157c16d --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Catalog.cs @@ -0,0 +1,66 @@ +using System; + +namespace MSHelpSystem.Core +{ + public class Help3Catalog + { + public Help3Catalog(string code, string version, string locale, string name, string catPath, string contPath, string brandPackage) + { + productCode = code; + productVersion = version; + productLocale = locale; + displayName = (string.IsNullOrEmpty(name)) ? code:name; + catalogPath = catPath; + contentPath = contPath; + brandingPackage = brandPackage; + } + + string productCode; + string productVersion; + string productLocale; + string displayName; + string catalogPath; + string contentPath; + string brandingPackage; + + public string ProductCode + { + get { return productCode; } + } + + public string ProductVersion + { + get { return productVersion; } + } + + public string Locale + { + get { return productLocale.ToUpper(); } + } + + public string DisplayName + { + get { return displayName; } + } + + public string CatalogPath + { + get { return catalogPath; } + } + + public string ContentPath + { + get { return contentPath; } + } + + public string BrandingPackage + { + get { return brandingPackage; } + } + + public override string ToString() + { + return string.Format(@"{0}/{1}/{2}", productCode, productVersion, productLocale); + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/Help3Environment.cs b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Environment.cs new file mode 100644 index 0000000000..82417852c9 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Environment.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using Microsoft.Win32; +using ICSharpCode.Core; +using MSHelpSystem.Helper; + +namespace MSHelpSystem.Core +{ + internal sealed class Help3Environment + { + Help3Environment() + { + } + + public static bool IsHelp3ProtocolRegistered + { + get + { + try { + RegistryKey hkcr = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64).OpenSubKey(@"MS-XHelp\shell\open\command", false); + string helpLibAgent = (string)hkcr.GetValue("", string.Empty); + hkcr.Close(); + return (!string.IsNullOrEmpty(helpLibAgent)); + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return false; + } + } + + public static bool IsLocalStoreInitialized + { + get + { + string localStore = LocalStore; + return (!string.IsNullOrEmpty(localStore) && Directory.Exists(localStore)); + } + } + + public static string LocalStore + { + get + { + try { + RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Help\v1.0", false); + string localStore = (string)hklm.GetValue("LocalStore", string.Empty); + hklm.Close(); + return localStore; + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return string.Empty; + } + } + + public static string BuildLocalStoreFolder + { + get { return Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); } + } + + public static string AppRoot + { + get + { + try { + RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Help\v1.0", false); + string appRoot = (string)hklm.GetValue("AppRoot", string.Empty); + hklm.Close(); + return appRoot; + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return string.Empty; + } + } + + public static string ManifestFolder + { + get + { + string manifestFolder = LocalStore; + if (string.IsNullOrEmpty(manifestFolder)) return string.Empty; + manifestFolder = System.IO.Path.Combine(manifestFolder, "manifest"); + if (Directory.Exists(manifestFolder)) return manifestFolder; + else return string.Empty; + } + } + + public static bool IsLocalHelp + { + get { return HelpClientWatcher.IsLocalHelp; } + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/Help3Service.cs b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Service.cs new file mode 100644 index 0000000000..db4b5322e7 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/Help3Service.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using ICSharpCode.Core; +using MSHelpSystem.Helper; + +namespace MSHelpSystem.Core +{ + public sealed class Help3Service + { + Help3Service() + { + HelpLibraryAgent.Start(); + } + + static Help3Service() + { + Help3Service.CatalogsUpdated += new EventHandler(Help3HasUpdatedTheCatalogs); + Help3Service.CatalogChanged += new EventHandler(Help3ActiveCatalogIdChanged); + Help3Service.ConfigurationUpdated += new EventHandler(Help3ConfigurationUpdated); + LoadHelpConfiguration(); + UpdateCatalogs(); + if (config.OfflineMode) HelpClientWatcher.EnableLocalHelp(); + else HelpClientWatcher.EnableOnlineHelp(); + } + + static List catalogs = new List(); + static Help3Catalog activeCatalog = null; + static Help3Configuration config = new Help3Configuration(); + + #region Read help catalogs + + static void UpdateCatalogs() + { + catalogs.Clear(); + if (Help3Environment.IsHelp3ProtocolRegistered && !string.IsNullOrEmpty(Help3Environment.ManifestFolder)) + { + try { + DirectoryInfo folder = new DirectoryInfo(Help3Environment.ManifestFolder); + FileInfo[] files = folder.GetFiles(@"queryManifest*.xml"); + foreach (FileInfo file in files) { + XmlDocument xml = new XmlDocument(); + xml.Load(file.FullName); + XmlNodeList n = xml.SelectNodes("/queryManifest[@version=\"1.0\"]/catalogs/catalog"); + foreach (XmlNode node in n) { + catalogs.Add( + new Help3Catalog(node.Attributes["productId"].InnerText, + node.Attributes["productVersion"].InnerText, + node.Attributes["productLocale"].InnerText, + node.Attributes["productDisplayName"].InnerText, + node.SelectSingleNode("catalogPath").InnerText, + node.SelectSingleNode("contentPath").InnerText, + node.SelectSingleNode("brandingPackageFileName").InnerText) + ); + } + } + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + } + OnCatalogsUpdated(EventArgs.Empty); + } + + static void Help3HasUpdatedTheCatalogs(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(config.ActiveCatalogId)) { + config.ActiveCatalogId = (catalogs.Count > 0) ? catalogs[0].ProductCode:string.Empty; + } + activeCatalog = (string.IsNullOrEmpty(config.ActiveCatalogId)) ? null:FindCatalogByItsString(config.ActiveCatalogId); + } + + static void Help3ActiveCatalogIdChanged(object sender, EventArgs e) + { + activeCatalog = (catalogs.Count > 0) ? FindCatalogByItsString(config.ActiveCatalogId) : null; + } + + static void Help3ConfigurationUpdated(object sender, EventArgs e) + { + if (config.OfflineMode) { + HelpClientWatcher.EnableLocalHelp(); + } + else { + HelpClientWatcher.EnableOnlineHelp(); + HelpLibraryAgent.Stop(); + } + } + + #endregion + + + public static int Count + { + get + { + return catalogs.Count; + } + } + + public static ReadOnlyCollection Items + { + get + { + ReadOnlyCollection c = new ReadOnlyCollection(catalogs); + return c; + } + } + + public static Help3Catalog FindCatalogByProductCode(string productCode) + { + foreach (Help3Catalog catalog in catalogs) + { + if (string.Compare(productCode, catalog.ProductCode, true) == 0) + { + return catalog; + } + } + return null; + } + + public static Help3Catalog FindCatalogByDisplayName(string displayName) + { + foreach (Help3Catalog catalog in catalogs) + { + if (string.Compare(displayName, catalog.DisplayName, true) == 0) + { + return catalog; + } + } + return null; + } + + public static Help3Catalog FindCatalogByItsString(string stringValue) + { + foreach (Help3Catalog catalog in catalogs) + { + if (string.Compare(stringValue, catalog.ToString()) == 0) + { + return catalog; + } + } + return null; + } + + public static string ActiveCatalogId + { + get + { + return config.ActiveCatalogId; + } + set + { + config.ActiveCatalogId = value; + OnCatalogChanged(EventArgs.Empty); + } + } + + public static Help3Catalog ActiveCatalog + { + get + { + return activeCatalog; + } + } + + public static Help3Configuration Config + { + get { return config; } + } + + #region Configuration + + public static void LoadHelpConfiguration() + { + string configFile = System.IO.Path.Combine(PropertyService.ConfigDirectory, "mshelpsystem.xml"); + if (!File.Exists(configFile)) { + return; + } + try { + XmlSerializer serialize = new XmlSerializer(typeof(Help3Configuration)); + TextReader file = new StreamReader(configFile); + config = (Help3Configuration)serialize.Deserialize(file); + file.Close(); + LoggingService.Info("Help 3.0: Configuration successfully loaded"); + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + OnConfigurationUpdated(EventArgs.Empty); + } + + public static void SaveHelpConfiguration() + { + string configFile = System.IO.Path.Combine(PropertyService.ConfigDirectory, "mshelpsystem.xml"); + try { + XmlSerializer serialize = new XmlSerializer(typeof(Help3Configuration)); + TextWriter file = new StreamWriter(configFile); + serialize.Serialize(file, config); + file.Close(); + LoggingService.Info("Help 3.0: Configuration successfully saved"); + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + OnConfigurationUpdated(EventArgs.Empty); + } + + #endregion + + #region Event handling + + public static event EventHandler CatalogsUpdated; + public static event EventHandler CatalogChanged; + public static event EventHandler ConfigurationUpdated; + + static void OnCatalogsUpdated(EventArgs e) + { + LoggingService.Debug("Help 3.0: \"OnCatalogsUpdated\" event raised"); + if (CatalogsUpdated != null) CatalogsUpdated(null, e); + } + + static void OnCatalogChanged(EventArgs e) + { + LoggingService.Debug("Help 3.0: \"OnCatalogChanged\" event raised"); + if (CatalogChanged != null) CatalogChanged(null, e); + } + + static void OnConfigurationUpdated(EventArgs e) + { + LoggingService.Debug("Help 3.0: \"OnConfigurationUpdated\" event raised"); + if (ConfigurationUpdated != null) ConfigurationUpdated(null, e); + } + + #endregion + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/HelpLibraryAgent.cs b/src/AddIns/Misc/HelpViewer/Source/Core/HelpLibraryAgent.cs new file mode 100644 index 0000000000..8ac4da8279 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/HelpLibraryAgent.cs @@ -0,0 +1,129 @@ +using System; +using System.Diagnostics; +using System.IO; +using Microsoft.Win32; +using ICSharpCode.Core; + +namespace MSHelpSystem.Core +{ + internal sealed class HelpLibraryAgent + { + HelpLibraryAgent() + { + } + + public static bool IsRunning + { + get + { + Process[] agents = Process.GetProcessesByName("HelpLibAgent"); + LoggingService.Debug(string.Format("Help 3.0: {0} {1} of HelpLibraryAgent.exe found", agents.Length, (agents.Length == 1)?"process":"processes")); + return agents.Length > 0; + } + } + + public static string Agent + { + get + { + if (string.IsNullOrEmpty(Help3Environment.AppRoot)) return string.Empty; + string agent = Path.Combine(Help3Environment.AppRoot, "HelpLibAgent.exe"); + LoggingService.Debug(string.Format("Help 3.0: Help library agent is \"{0}\"", agent)); + return (File.Exists(agent)) ? agent : string.Empty; + } + } + + public static int PortNumber + { + get + { + try { + RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Help\v1.0", false); + string port = (string)hklm.GetValue("AgentPort", "47873"); + hklm.Close(); + return Convert.ToInt32(port); + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return 47873; // This is the DEFAULT port number! + } + } + + public static int ProcessId + { + get + { + Process[] agents = Process.GetProcessesByName("HelpLibAgent"); + int processId = (agents.Length > 0) ? agents[0].Id:0; + LoggingService.Debug(string.Format("Help 3.0: Port number is \"{0}\"", processId)); + return processId; + } + } + + public static string CurrentViewer + { + get + { + string viewer = string.Empty; + try { + RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\Microsoft\Help\v1.0", false); + viewer = (string)hklm.GetValue("HelpViewerProgID", string.Empty); + hklm.Close(); + + if (string.IsNullOrEmpty(viewer)) { + RegistryKey hkcr = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64).OpenSubKey(@"HTTP\shell\open\command", false); + viewer = (string)hkcr.GetValue("", string.Empty); + hkcr.Close(); + if (viewer.LastIndexOf(' ') > 0) viewer = viewer.Substring(0, viewer.LastIndexOf(' ')); + viewer = viewer.Trim("\"".ToCharArray()); + } + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + LoggingService.Debug(string.Format("Help 3.0: Default viewer is \"{0}\"", viewer)); + return viewer; + } + } + + public static bool Start() + { + if (IsRunning) return true; + if (!Help3Environment.IsLocalHelp) return false; + try { + Process p = Process.Start(Agent); + p.WaitForInputIdle(); + LoggingService.Info("Help 3.0: Help library agent started"); + return IsRunning; + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return false; + } + + public static bool Stop() + { + return Stop(true); + } + + public static bool Stop(bool waitForExit) + { + try { + Process[] agents = Process.GetProcessesByName("HelpLibAgent"); + LoggingService.Debug(string.Format("Help 3.0: {0} {1} of HelpLibraryAgent.exe found", agents.Length, (agents.Length == 1)?"process":"processes")); + + foreach (Process agent in agents) { + agent.Kill(); + if (waitForExit) agent.WaitForExit(); + } + LoggingService.Info("Help 3.0: Help library agent stopped"); + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return true; + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Core/NativeMethods.cs b/src/AddIns/Misc/HelpViewer/Source/Core/NativeMethods.cs new file mode 100644 index 0000000000..d1a3c18b23 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Core/NativeMethods.cs @@ -0,0 +1,58 @@ +using System; +using System.Runtime.InteropServices; + +namespace MSHelpSystem.Core.Native +{ + internal sealed class NativeMethods + { + NativeMethods() + { + } + + [DllImport("Wtsapi32.dll")] + internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned); + + [DllImport("Wtsapi32.dll", ExactSpelling = true, SetLastError = false)] + public static extern void WTSFreeMemory(IntPtr memory); + + internal enum WTSInfoClass + { + WTSInitialProgram, + WTSApplicationName, + WTSWorkingDirectory, + WTSOEMId, + WTSSessionId, + WTSUserName, + WTSWinStationName, + WTSDomainName, + WTSConnectState, + WTSClientBuildNumber, + WTSClientName, + WTSClientDirectory, + WTSClientProductId, + WTSClientHardwareId, + WTSClientAddress, + WTSClientDisplay, + WTSClientProtocolType + } + + internal static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; + internal static int WTS_CURRENT_SESSION = -1; + + public static int GetSessionId() + { + IntPtr pSessionId = IntPtr.Zero; + Int32 sessionId = 0; + uint bytesReturned; + + try { + bool returnValue = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSInfoClass.WTSSessionId, out pSessionId, out bytesReturned); + if (returnValue) sessionId = Marshal.ReadInt32(pSessionId); + } + finally { + if (pSessionId != IntPtr.Zero) WTSFreeMemory(pSessionId); + } + return sessionId; + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml b/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml new file mode 100644 index 0000000000..e7a7afbee4 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml.cs b/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml.cs new file mode 100644 index 0000000000..4fed1bfa26 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Help3OptionsPanel.xaml.cs @@ -0,0 +1,79 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Forms; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using MSHelpSystem.Core; +using MSHelpSystem.Helper; + +namespace MSHelpSystem +{ + public partial class Help3OptionsPanel : OptionPanel + { + public Help3OptionsPanel() + { + InitializeComponent(); + LoadCatalogs(); + onlineMode.IsChecked = !Help3Service.Config.OfflineMode; + } + + void LoadCatalogs() + { + if (Help3Environment.IsLocalHelp) HelpLibraryAgent.Start(); + + help3Catalogs.Items.Clear(); + if (Help3Service.Count > 0) { + foreach (Help3Catalog catalog in Help3Service.Items) { + LoggingService.Debug(string.Format("Help 3.0: Found help catalog \"{0}\"", catalog.ToString())); + ComboBoxItem cbi = new ComboBoxItem(); + cbi.Content = catalog.ToString(); + help3Catalogs.Items.Add(cbi); + } + } + // TODO: localization needed for "Installed help catalogs" + groupBox1.Header = string.Format("{0} ({1})", "Installed Help catalogs", Help3Service.Count); + + if (help3Catalogs.Items.Count == 0) help3Catalogs.SelectedIndex = 0; + else { + foreach (ComboBoxItem item in help3Catalogs.Items) { + if (string.Compare((string)item.Content, Help3Service.ActiveCatalog.ToString(), true) == 0) { + help3Catalogs.SelectedItem = item; + break; + } + } + // TODO: There has to be a much more elegant way to select the catalog?! + } + help3Catalogs.IsEnabled = (help3Catalogs.Items.Count > 1 && Help3Service.Config.OfflineMode); + } + + void Help3CatalogsSelectionChanged(object sender, SelectionChangedEventArgs e) + { + ComboBoxItem selectedItem = (ComboBoxItem)help3Catalogs.SelectedItem; + if (selectedItem == null) return; + string activeCatalog = (string)selectedItem.Content; + if (!string.IsNullOrEmpty(activeCatalog)) Help3Service.ActiveCatalogId = activeCatalog; + } + + void Help3OfflineModeClicked(object sender, RoutedEventArgs e) + { + LoggingService.Info("Help 3.0: Setting help mode to \"offline\""); + Help3Service.Config.OfflineMode = true; + help3Catalogs.IsEnabled = (help3Catalogs.Items.Count > 1 && Help3Service.Config.OfflineMode); + } + + void Help3OnlineModeClicked(object sender, RoutedEventArgs e) + { + LoggingService.Info("Help 3.0: Setting help mode to \"online\""); + Help3Service.Config.OfflineMode = false; + help3Catalogs.IsEnabled = false; + } + + public override bool SaveOptions() + { + Help3Service.SaveHelpConfiguration(); + return true; + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/HelpMenu.cs b/src/AddIns/Misc/HelpViewer/Source/HelpMenu.cs new file mode 100644 index 0000000000..f74794306e --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/HelpMenu.cs @@ -0,0 +1,15 @@ +using System; +using MSHelpSystem.Core; +using ICSharpCode.Core; + +namespace MSHelpSystem.SharpDevelopMenu +{ + public class DisplayCatalogCommand : AbstractMenuCommand + { + public override void Run() + { + LoggingService.Info("Help 3.0: Calling menu command \"DisplayHelp.Catalog()\""); + DisplayHelp.Catalog(); + } + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/Helper/Help3Configuration.cs b/src/AddIns/Misc/HelpViewer/Source/Helper/Help3Configuration.cs new file mode 100644 index 0000000000..cd319fa8b6 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Helper/Help3Configuration.cs @@ -0,0 +1,31 @@ +using System; +using System.Xml; +using System.Xml.Serialization; + +namespace MSHelpSystem.Helper +{ + [XmlRoot("mshelpsystem")] + public class Help3Configuration + { + public Help3Configuration() + { + } + + string activeCatalogId = string.Empty; + bool offlineMode = true; + + [XmlElement("activeCatalog")] + public string ActiveCatalogId + { + get { return activeCatalogId; } + set { activeCatalogId = value; } + } + + [XmlElement("offlineMode")] + public bool OfflineMode + { + get { return offlineMode; } + set { offlineMode = value; } + } + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/Helper/HelpClientWatcher.cs b/src/AddIns/Misc/HelpViewer/Source/Helper/HelpClientWatcher.cs new file mode 100644 index 0000000000..d4e7714b52 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Helper/HelpClientWatcher.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; +using System.Configuration; +using System.Threading; +using ICSharpCode.Core; +using MSHelpSystem.Core; + +namespace MSHelpSystem.Helper +{ + internal sealed class HelpClientWatcher + { + HelpClientWatcher() + { + } + + static HelpClientWatcher() + { + if (!Directory.Exists(clientPath)) { + Directory.CreateDirectory(clientPath); + } + clientFileChanged = new FileSystemWatcher(clientPath); + clientFileChanged.NotifyFilter = NotifyFilters.LastWrite; + clientFileChanged.Filter = "HelpClient.cfg"; + clientFileChanged.Changed += new FileSystemEventHandler(OnFileChanged); + clientFileChanged.Created += new FileSystemEventHandler(OnFileChanged); + clientFileChanged.EnableRaisingEvents = true; + + helpMode = GetHelpMode(); + } + + static string clientPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Microsoft\HelpLibrary"); + static FileSystemWatcher clientFileChanged = null; + static string helpMode = string.Empty; + + static void OnFileChanged(object sender, FileSystemEventArgs e) + { + helpMode = GetHelpMode(); + Help3Service.Config.OfflineMode = IsLocalHelp; + } + + public static bool IsLocalHelp + { + get { return string.Compare("offline", helpMode, true) == 0; } + } + + public static void EnableLocalHelp() + { + helpMode = "offline"; + SetHelpMode(); + } + + public static void EnableOnlineHelp() + { + helpMode = "online"; + SetHelpMode(); + } + + static string GetHelpMode() + { + Configuration config = null; + try { + string clientFile = Path.Combine(clientPath, "HelpClient.cfg"); + if (File.Exists(clientFile)) { + ExeConfigurationFileMap fm = new ExeConfigurationFileMap(); + fm.ExeConfigFilename = clientFile; + try { + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + catch (ConfigurationErrorsException) { + Thread.Sleep(0x3e8); + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + if (config != null) { + AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings"); + string tmp = section.Settings["helpMode"].Value; + return (string.IsNullOrEmpty(tmp)) ? "offline":tmp; + } + } + else { + ExeConfigurationFileMap fm = new ExeConfigurationFileMap(); + fm.ExeConfigFilename = Path.Combine(Help3Environment.AppRoot, "HelpClient.cfg"); + try { + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + catch (ConfigurationErrorsException) { + Thread.Sleep(0x3e8); + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + if (config != null) { + AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings"); + string tmp = section.Settings["helpMode"].Value; + return (string.IsNullOrEmpty(tmp)) ? "offline":tmp; + } + } + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + return "offline"; + } + + static void SetHelpMode() + { + clientFileChanged.EnableRaisingEvents = false; + LoggingService.Info(string.Format("Help 3.0: Trying to set Help mode to \"{0}\"", helpMode)); + + Configuration config = null; + try { + string clientFile = Path.Combine(clientPath, "HelpClient.cfg"); + if (!File.Exists(clientFile)) { + string sourceFile = Path.Combine(Help3Environment.AppRoot, "HelpClient.cfg"); + if (!Directory.Exists(clientPath)) { + Directory.CreateDirectory(clientPath); + } + File.Copy(sourceFile, clientFile); + Thread.Sleep(0x3e8); + } + if (File.Exists(clientFile)) { + ExeConfigurationFileMap fm = new ExeConfigurationFileMap(); + fm.ExeConfigFilename = clientFile; + try { + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + catch (ConfigurationErrorsException) { + Thread.Sleep(0x3e8); + config = ConfigurationManager.OpenMappedExeConfiguration(fm, ConfigurationUserLevel.None); + } + if (config != null) { + AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings"); + section.Settings["helpMode"].Value = helpMode; + config.Save(); + } + } + } + catch (Exception ex) { + LoggingService.Error(string.Format("Help 3.0: {0}", ex.ToString())); + } + clientFileChanged.EnableRaisingEvents = true; + } + } +} \ No newline at end of file diff --git a/src/AddIns/Misc/HelpViewer/Source/Helper/ProjectLanguages.cs b/src/AddIns/Misc/HelpViewer/Source/Helper/ProjectLanguages.cs new file mode 100644 index 0000000000..47e7e1dbe9 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/Helper/ProjectLanguages.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; + +namespace MSHelpSystem.Helper +{ + internal sealed class ProjectLanguages + { + ProjectLanguages() + { + } + + #region Supported project languages + + static Dictionary languages = InitializeLanguages(); + + static Dictionary InitializeLanguages() + { + Dictionary result = new Dictionary(); + result.Add("C++", "C%2B%2B"); + result.Add("C#", "CSharp"); + result.Add("VBNet", "VB"); + return result; + } + + #endregion + + public static string Formatted() + { + string output = string.Empty; + if (ProjectService.CurrentProject != null) { + string devLang = ProjectService.CurrentProject.Language; + if (string.IsNullOrEmpty(devLang)) { throw new ArgumentNullException("devLang"); } + output = devLang; + + if (!languages.ContainsKey(devLang) || !languages.TryGetValue(devLang, out output)) { + output = devLang; + } + LoggingService.Debug(string.Format("Help 3.0: Project language \"{0}\" formatted to \"{1}\"", devLang, output)); + } + return output.ToLower(); + } + + public static string FormattedAsHttpParam() + { + string devLang = Formatted(); + if (string.IsNullOrEmpty(devLang)) return string.Empty; + else return string.Format("&category=DevLang%3a{0}", devLang); + } + } +} diff --git a/src/AddIns/Misc/HelpViewer/Source/MSHelp3Provider.cs b/src/AddIns/Misc/HelpViewer/Source/MSHelp3Provider.cs new file mode 100644 index 0000000000..6b945386e6 --- /dev/null +++ b/src/AddIns/Misc/HelpViewer/Source/MSHelp3Provider.cs @@ -0,0 +1,30 @@ +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using MSHelpSystem.Core; + +namespace MSHelpSystem +{ + public class MSHelp3Provider : HelpProvider + { + public override bool TryShowHelp(string fullTypeName) + { + if (string.IsNullOrEmpty(fullTypeName)) { + throw new ArgumentNullException("fullTypeName"); + } + LoggingService.Info(string.Format("Help 3.0: Calling \"TryShowHelp\" with {0}", fullTypeName)); + DisplayHelp.ContextualHelp(fullTypeName); + return true; + } + + public override bool TryShowHelpByKeyword(string keyword) + { + if (string.IsNullOrEmpty(keyword)) { + throw new ArgumentNullException("keyword"); + } + LoggingService.Info(string.Format("Help 3.0: Calling \"TryShowHelpByKeyword\" with {0}", keyword)); + DisplayHelp.Keywords(keyword); + return true; + } + } +}