Index: class/Managed.Windows.Forms/System.Windows.Forms/Help.cs
===================================================================
--- class/Managed.Windows.Forms/System.Windows.Forms/Help.cs	(revision 72075)
+++ class/Managed.Windows.Forms/System.Windows.Forms/Help.cs	(working copy)
@@ -21,6 +21,7 @@
 //
 // Authors:
 //	Peter Bartok	(pbartok@novell.com)
+//	George Giolfan	(georgegiofan@yahoo.com)
 //
 //
 
@@ -28,6 +29,8 @@
 
 using System;
 using System.Drawing;
+using System.Diagnostics;
+using System.IO;
 
 namespace System.Windows.Forms {
 	public class Help {
@@ -45,13 +48,43 @@
 			ShowHelp(parent, url, navigator, null);
 		}
 
-		[MonoTODO("Create glue code to tie into libCHM")]
-		public static void ShowHelp(Control parent, string url, HelpNavigator command, object param) {
-			MessageBox.Show(parent, (string)Locale.GetText("Help (" + command +
-					(param != null ? "(" + param + ")" : String.Empty) +
-					") not yet implemented"), (string)Locale.GetText("Popup Help"),
-					MessageBoxButtons.OK, MessageBoxIcon.Stop);
-		}
+        public static void ShowHelp(Control parent, string url, HelpNavigator command, object 
+#if NET_2_0
+            parameter
+#else
+            param
+#endif
+        ) {
+#if NET_2_0
+            object param = parameter;
+#endif
+            const string HelpUrlIsNotValid = "Help URL '{0}' is not valid.";
+            if (url == null || url.Length == 0)
+                throw new ArgumentException(string.Format(HelpUrlIsNotValid, null), "url");
+            string scheme;
+            string local_path;
+            try {
+                Uri uri = new Uri(url);
+                if (uri.Scheme == "file") {
+                    scheme = "file";
+                    local_path = uri.LocalPath;
+                } else
+                    return;
+            } catch (UriFormatException ex) {
+                scheme = null;
+                local_path = url;
+            }
+            if (string.Equals(new FileInfo(local_path).Extension, ".chm", StringComparison.InvariantCultureIgnoreCase))
+                if (param is int)
+                    throw new ArgumentException("InvalidArgument=Value of 'Integer' is not valid for 'param'.", "param");
+                else if (param == null || param is string)
+                    XplatUI.HtmlHelp(parent, scheme + (File.Exists(local_path) ? new FileInfo(local_path).FullName : local_path), command, (string)param);
+            else
+                if (new FileInfo(local_path).Exists)
+                    Process.Start(url);
+                else
+                    throw new ArgumentException(string.Format(HelpUrlIsNotValid, url), "url");
+        }
 
 		public static void ShowHelp(Control parent, string url, string keyword) {
 			if (keyword == null || keyword == String.Empty) {
@@ -64,10 +97,56 @@
 			ShowHelp(parent, url, HelpNavigator.Index, null);
 		}
 
-		[MonoTODO("Create glue code to tie into libCHM")]
 		public static void ShowPopup(Control parent, string caption, Point location) {
-			MessageBox.Show(parent, (string)Locale.GetText("Popup Help not yet implemented"), (string)Locale.GetText("Popup Help"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
+            //FIXME: How is parent used?
+            PopupForm.Show(caption, location);
 		}
 		#endregion	// Public Static Methods
-	}
-}
+        
+        class PopupForm : Form {
+            string caption;
+            Rectangle black_border_rectangle;
+            Rectangle gray_border_rectangle;
+            Rectangle background_rectagle;
+            Point caption_location;
+            PopupForm(string caption, Point location) {
+                this.caption = caption;
+                FormBorderStyle = FormBorderStyle.None;
+                StartPosition = FormStartPosition.Manual;
+                Graphics g = CreateGraphics();
+                SizeF text_size = g.MeasureString(caption, Font, Screen.FromControl(this).Bounds.Width);
+                g.Dispose();
+                const int margin_width = 3;
+                const int caption_distance = margin_width + 2;
+                Rectangle caption_rectagle = new Rectangle(caption_distance, caption_distance, (int)text_size.Width, (int)text_size.Height);
+                const int caption_extra_space = 4 + 2 * margin_width;
+                Size = new Size(caption_rectagle.Width + caption_extra_space, caption_rectagle.Height + caption_extra_space);
+                const int margin_size = 2 * margin_width;
+                background_rectagle = new Rectangle(2, 2, caption_rectagle.Width + margin_size, caption_rectagle.Height + margin_size);
+                black_border_rectangle = new Rectangle(0, 0, background_rectagle.Width + 3, background_rectagle.Height + 3);
+                gray_border_rectangle = new Rectangle(1, 1, background_rectagle.Width + 1, background_rectagle.Height + 1);
+                caption_location = caption_rectagle.Location;
+                DesktopLocation = new Point(location.X - Width / 2, location.Y - Height / 4);
+            }
+            protected override void OnPaint(PaintEventArgs e) {
+                base.OnPaint(e);
+                Graphics g = e.Graphics;
+                g.DrawRectangle(Pens.Black, black_border_rectangle);
+                g.DrawRectangle(Pens.LightGray, gray_border_rectangle);
+                g.FillRectangle(Brushes.White, background_rectagle);
+                g.DrawString(caption, Font, Brushes.Black, caption_location);
+            }
+            protected override void OnMouseDown(MouseEventArgs e) {
+                base.OnMouseDown(e);
+                Close();
+            }
+            protected override void OnDeactivate(EventArgs e) {
+                base.OnDeactivate(e);
+                Close();
+            }
+            public static void Show(string caption, Point location) {
+                new PopupForm(caption, location).Show();
+            }
+        }
+    }
+}
\ No newline at end of file
Index: class/Managed.Windows.Forms/System.Windows.Forms/XplatUI.cs
===================================================================
--- class/Managed.Windows.Forms/System.Windows.Forms/XplatUI.cs	(revision 72075)
+++ class/Managed.Windows.Forms/System.Windows.Forms/XplatUI.cs	(working copy)
@@ -1042,8 +1042,12 @@
 		internal static void Version() {
 			Console.WriteLine("Xplat version $Revision: $");
 		}
-		#endregion	// Public Static Methods
 
+        internal static void HtmlHelp(Control parent, string url, HelpNavigator command, string param) {
+            driver.HtmlHelp(parent, url, command, param);
+        }
+        #endregion	// Public Static Methods
+
 		#region	Delegates
 		public delegate bool ClipboardToObject(int type, IntPtr data, out object obj);
 		public delegate bool ObjectToClipboard(ref int type, object obj, out byte[] data);
Index: class/Managed.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs
===================================================================
--- class/Managed.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs	(revision 72075)
+++ class/Managed.Windows.Forms/System.Windows.Forms/XplatUIDriver.cs	(working copy)
@@ -322,6 +322,19 @@
 			dest_dc.DrawImage ((Bitmap)offscreen_drawable, r, r, GraphicsUnit.Pixel);
 		}
 
+        [MonoTODO("Create glue code to tie into libCHM")]
+        internal virtual void HtmlHelp(Control parent, string url, HelpNavigator command, string param) {
+            // Assumes the CHM Reader extension.
+            try {
+                System.Diagnostics.Process.Start("firefox", "\"chm:" + (url.StartsWith("file:") ? url : "file:" + url) + (param == null ? null : "!" + (param.StartsWith("/") ? param : "/" + param)) + "\"");
+            } catch {
+                MessageBox.Show(parent, (string)Locale.GetText("Help (" + command +
+                        (param != null ? "(" + param + ")" : String.Empty) +
+                        ") not yet implemented"), (string)Locale.GetText("Popup Help"),
+                        MessageBoxButtons.OK, MessageBoxIcon.Stop);
+            }
+        }
+
 #endregion	// XplatUI Driver Methods
 	}
 
Index: class/Managed.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs
===================================================================
--- class/Managed.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs	(revision 72075)
+++ class/Managed.Windows.Forms/System.Windows.Forms/XplatUIWin32.cs	(working copy)
@@ -701,9 +701,58 @@
 			LWA_ALPHA			= 0x2,
 		}
 
-		
-		#endregion
+        enum HtmlHelpCommands {
+            HH_DISPLAY_TOPIC    = 0x0000,
+            HH_DISPLAY_TOC      = 0x0001, 
+            HH_DISPLAY_INDEX    = 0x0002,  
+            HH_DISPLAY_SEARCH   = 0x0003,
+            HH_KEYWORD_LOOKUP   = 0x000D,
+#if NET_2_0
+            HH_HELP_CONTEXT     = 0x000F,
+            HH_ALINK_LOOKUP     = 0x0013,
+#endif
+        }
 
+        struct HH_AKLINK {
+            public HH_AKLINK(string keyword) {
+                cbStruct = Marshal.SizeOf(typeof(HH_AKLINK));
+                const int FALSE = 0;
+                fReserved = FALSE;
+                pszKeywords = keyword;
+                pszUrl = null;
+                pszMsgText = null;
+                pszMsgTitle = null;
+                pszWindow = null;
+                const int TRUE = 1;
+                fIndexOnFail = TRUE;
+            }
+            int cbStruct;
+            int fReserved;
+            string pszKeywords;
+            string pszUrl;
+            string pszMsgText;
+            string pszMsgTitle;
+            string pszWindow;
+            int fIndexOnFail;
+        }
+
+        struct HH_FTS_QUERY {
+            static public HH_FTS_QUERY CreateNew() {
+                HH_FTS_QUERY instance = new HH_FTS_QUERY();
+                instance.cbStruct = Marshal.SizeOf(typeof(HH_FTS_QUERY));
+                return instance;
+            }
+            int cbStruct;
+            int fUniCodeStrings;
+            string pszSearchQuery;
+            long iProximity;
+            int fStemmedSearch;
+            int fTitleOnly;
+            int fExecute;
+            string pszWindow;
+        }
+        #endregion
+
 		#region Constructor & Destructor
 		private XplatUIWin32() {
 			WNDCLASS	wndClass;
@@ -2680,6 +2729,49 @@
 		}
 
 		internal override event EventHandler Idle;
+        
+        internal override void HtmlHelp(Control parent, string url, HelpNavigator command, string param) {
+            //FIXME: Sometimes SWF calls HtmlHelp more than one time, probably if the first call fails.
+            IntPtr parent_handle = parent == null ? IntPtr.Zero : parent.Handle; 
+            switch (command) {
+                case HelpNavigator.Topic:
+                    Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_TOPIC, param);
+                    break;
+                case HelpNavigator.TableOfContents:
+                    Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_TOC, IntPtr.Zero);
+                    break;
+                //LAMESPEC: "You can use the param parameter to provide further refinement of the Topic, TopicID, KeywordIndex, or AssociateIndex command. If the value specified in the command parameter is TableOfContents, Index, or Find, this value should be a null reference (Nothing in Visual Basic)." In the example on the HelpNavigator page, whatever is in the text box is passed as param (and in the case of HelpNavigator.Index, it does something).
+                case HelpNavigator.Index:
+                    Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_INDEX, param);
+                    break;
+                case HelpNavigator.Find:
+                    HH_FTS_QUERY query = HH_FTS_QUERY.CreateNew();
+                    Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_SEARCH, ref query);
+                    break;
+                case HelpNavigator.KeywordIndex:
+                    HH_AKLINK keyword = new HH_AKLINK(param);
+                    Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_KEYWORD_LOOKUP, ref keyword);
+                    break;
+#if NET_2_0
+                case HelpNavigator.TopicId:
+                    int topic_id;
+                    if (int.TryParse(param, out topic_id))
+                        Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_HELP_CONTEXT, topic_id);
+                    else
+                        Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_INDEX, IntPtr.Zero);
+                    break;
+                case HelpNavigator.AssociateIndex:
+                    if (string.IsNullOrEmpty(param))
+                        Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_DISPLAY_INDEX, IntPtr.Zero);
+                    else {
+                        //FIXME: SWF passes HH_DISPLAY_TOPIC first.
+                        HH_AKLINK keywordAssociateIndex = new HH_AKLINK(param);
+                        Win32HtmlHelp(parent_handle, url, HtmlHelpCommands.HH_ALINK_LOOKUP, ref keywordAssociateIndex);
+                    }
+                    break;
+#endif
+            }
+        }
 		#endregion	// Public Static Methods
 
 		#region Win32 Imports
@@ -3052,6 +3144,21 @@
 
 		[DllImport ("gdi32.dll", EntryPoint="CreateCompatibleBitmap", CallingConvention=CallingConvention.StdCall)]
 		internal static extern IntPtr Win32CreateCompatibleBitmap (IntPtr hdc, int nWidth, int nHeight);
-		#endregion
+        
+        [DllImport("hhctrl.ocx", EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
+        static extern IntPtr Win32HtmlHelp(IntPtr hwndCaller, string pszFile, HtmlHelpCommands uCommand, IntPtr dwData);
+        
+        [DllImport("hhctrl.ocx", EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
+        static extern IntPtr Win32HtmlHelp(IntPtr hwndCaller, string pszFile, HtmlHelpCommands uCommand, string dwData);
+        
+        [DllImport("hhctrl.ocx", EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
+        static extern IntPtr Win32HtmlHelp(IntPtr hwndCaller, string pszFile, HtmlHelpCommands uCommand, ref HH_AKLINK dwData);
+
+        [DllImport("hhctrl.ocx", EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
+        static extern IntPtr Win32HtmlHelp(IntPtr hwndCaller, string pszFile, HtmlHelpCommands uCommand, int dwData);
+
+        [DllImport("hhctrl.ocx", EntryPoint = "HtmlHelpW", CharSet = CharSet.Unicode)]
+        static extern IntPtr Win32HtmlHelp(IntPtr hwndCaller, string pszFile, HtmlHelpCommands uCommand, ref HH_FTS_QUERY dwData);
+        #endregion
 	}
 }
