Click here to Skip to main content
15,891,888 members
Articles / Desktop Programming / Windows Forms

Context Help authoring anywhere/anytime/anyone for .NET application

Rate me:
Please Sign up or sign in to vote.
1.40/5 (3 votes)
6 Dec 2007CPOL3 min read 21K   119   19  
Write context Help anywhere/anytime/anyone for .NET application
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

namespace Slimzhao
{
	/// <summary>
	/// Summary description for EasyHelpString.
	/// </summary>
	public class EasyHelpString
	{
		/// <summary>
		/// HelpProvider, control vs helpstring
		/// </summary>
		internal static HelpProvider global_hlp_provider = new HelpProvider();

		static EasyHelpString()
		{
			try
			{
				string full_xml_name = Path.Combine(
					Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
					help_file);

				FromXml(full_xml_name, assem_lower_name_VS_ArrayList_of_FormControl);
			}
			catch
			{
			}
		}
		/// <summary>
		/// This uses ControlPaint.DrawReversibleFrame to highlight the given window
		/// </summary>
		internal static void FlashCurrentWindow(Control c) 
		{
			Point topleft = c.Location;
			if (c.Parent != null) 
			{
				topleft = c.Parent.PointToScreen(topleft);
			}
			Size size = c.Size;
			Rectangle r = new Rectangle(topleft, size);

			for (int i = 1; i <= 7; i++) 
			{
				ControlPaint.DrawReversibleFrame(r, Color.Red, FrameStyle.Thick);
				Thread.Sleep(100);
			}
			Thread.Sleep(250);  //extra delay at the end.
			ControlPaint.DrawReversibleFrame(r, Color.Red, FrameStyle.Thick);
		}
		/// <summary>
		/// Composer is negaviate the system.
		/// </summary>
		private static bool b_composing = true;
		internal static string help_file = "help.xml";

		/// <summary>
		/// Init a form more than 1 times is safe
		/// </summary>
		/// <param name="container">Actually an instance of Form</param>
		/// <param name="force_include">Controls force to include for adding context help, Note Label is default excluded</param>
		public static void InitHelpProvider(Control container, params Control[] force_include)
		{
			InitHelpProvider(container, force_include, null);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="container">Actually an instance of Form</param>
		/// <param name="force_include">Controls force to include for adding context help, Note Label is default excluded</param>
		/// <param name="force_exclude">Controls force to exclude for adding context help, the pervasive OK and cancel button maybe
		///  the possible candicate</param>
		public static void InitHelpProvider(Control container, Control[] force_include, Control[] force_exclude)
		{
			if( b_ever_call_AddNonParentUserControl == false)
			{
				throw new Exception(
					"You should call AddNonParentUserControl at least once before the first call of InitHelpProvider");
			}
			if( container == null )
				throw new ArgumentNullException("container");

			StackTrace st = null;
			if(false && b_composing )
			{
				st = new StackTrace();
				if(st.GetFrame(1).GetMethod().Name != "InitHelpProvider")
				{
					set_help_setting(container);
				}
			}

			foreach(Control c in container.Controls)
			{
				//bugfix: TabControl is not a ContainerControl, but can has Controls/Childs
				Type t = c.GetType();
				if( t == typeof(Label) &&
					(force_include == null || Array.IndexOf(force_include, c /* bugfix: c <-> t */) < 0) ) 
					continue;

				if( force_exclude != null && Array.IndexOf(force_exclude, c) > -1 )
					continue;

				if( c.Controls.Count > 0 &&
					s_non_parent_user_controls.Contains(c.GetType() ) == false )
				{
					InitHelpProvider(c, force_include, force_exclude);
				}
				else
				{
					set_help_setting( c );
				}
			}

			if( st != null && s_editor != null &&
				s_editor.Visible )
			{
				if(st.GetFrame(1).GetMethod().Name != "InitHelpProvider")
				{
					if(s_editor.Owner != null && s_editor.Owner.IsHandleCreated)
					{
						s_editor.Enabled = true;
					}
					s_editor.Hide();
				}
				
			}			
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="container">Actually an instance of Form</param>
		public static void InitHelpProvider(Control container)
		{
			Control[] includes = null;
			Control[] excludes = null;
			InitHelpProvider(container, includes, excludes);
		}

		/// <summary>
		/// NumericUpDown is composed by an TextBox and a pair of button, such a control should be
		/// considered as a final input facility, not a container.
		/// </summary>
		private static ArrayList s_non_parent_user_controls = new ArrayList();
		private static bool b_ever_call_AddNonParentUserControl = false;
		/// <summary>
		/// Add or remove the types which control should be considered as the final user control, such as
		/// the NumericUpDown, although it's composed of a TextBox and a pair of buttons
		/// </summary>
		/// <param name="add">Add or remove, Add control which is already added by other class is harmless</param>
		/// <param name="nonParentUserControl">can be null</param>
		public static void AddNonParentUserControl(bool add, Type[] nonParentUserControl)
		{
			b_ever_call_AddNonParentUserControl = true;
			if( nonParentUserControl == null)
			{
				return;
			}

			foreach(Type t in nonParentUserControl)
			{
				if( add )
				{
					if( s_non_parent_user_controls.Contains(t) == false )
					{//We need not to add the same element more than once
						s_non_parent_user_controls.Add( t );
					}
				}
				else
				{
					s_non_parent_user_controls.Remove( t );
					Debug.Assert( s_non_parent_user_controls.Contains(t) == false,
						string.Format("There's still a type of {0} after remove it", t.ToString() ));
				}
			}
		}

		/// <summary>
		/// Set help string(for current ui culture) to HelpProvider, from memory or control's name
		/// </summary>
		/// <param name="c"></param>
		private static void set_help_setting(Control c )
		{
			string help_str = "";
			string cached_help_str = get_cached_help_str(c, null);
			if( cached_help_str != null)
			{
				help_str = cached_help_str;
			}

			//Only set control with a name
			//For the non name control, programmer can use a separate Help Provider
			if( c.Name.Length > 0)
			{
				global_hlp_provider.SetShowHelp(c, true);
				Debug.Assert(c.Name.Length > 0, "Control.Name.Length < 1");
				global_hlp_provider.SetHelpString(c, help_str);

				//TODO: Check only add it once
				if( Control_VS_null.ContainsKey(c) == false)
				{
					c.HelpRequested += new HelpEventHandler(Global_HelpRequested);
					Control_VS_null[c] = null;
				}
			}
		}
		/// <summary>
		/// Key: Control instance which set_help_setting already add HelpEventHandler to it's HelpRequested
		/// Value: null, not use
		/// </summary>
		private static Hashtable Control_VS_null = new Hashtable();

		/// <summary>
		/// Get a help string for current UI Culture from in memory cached data( maybe from XML file or
		/// set by user)
		/// </summary>
		/// <param name="c"></param>
		/// <param name="lower_lang_str">zh-chs, if null, use current UI Culture's</param>
		/// <returns></returns>
		internal static string get_cached_help_str( Control c, string lower_lang_str )
		{
			Form form = c.FindForm();
			if(form == null)
			{
				Debug.Assert(false, "FindForm() = null");
				throw new NullReferenceException("FindForm() = null");
			}
			Type t = form.GetType();
			string lower_assem_name = Path.GetFileName(t.Assembly.Location).ToLower();
			string class_name = t.FullName;

			//Check Assembly
			if( assem_lower_name_VS_ArrayList_of_FormControl.ContainsKey(lower_assem_name) == false)
				return null;

			//Check Form's Full Type Name
			foreach(FormControl fc in 
				(assem_lower_name_VS_ArrayList_of_FormControl[lower_assem_name] as ArrayList) )
			{
				if( fc.FullFormName == class_name)
				{
					//get the lower lang str
					string lc_lang_str = lower_lang_str;
					if( lc_lang_str == null)
					{
						lc_lang_str = get_current_ui_lang_str();
					}

					Debug.Assert(lc_lang_str == "en" || lc_lang_str == "zh-chs" || lc_lang_str == "zh-cht",
						string.Format("Unexpected lang str: {0}", lc_lang_str));

					return fc.GetHelpStr(c.Name, //bugfix: change class_name to c.Name
						lc_lang_str);
				}
			}
			return null;
		}

		/// <summary>
		/// get zh-chs
		/// </summary>
		/// <returns></returns>
		internal static string get_current_ui_lang_str()
		{
			CultureInfo info = Thread.CurrentThread.CurrentUICulture;
			string lc_lang_str = info.TwoLetterISOLanguageName + "-" + info.ThreeLetterWindowsLanguageName;
			lc_lang_str = lc_lang_str.ToLower();
			if(lc_lang_str.StartsWith("en-"))
			{
				lc_lang_str = "en";
			}
			return lc_lang_str;
		}

		private static EditHelpString s_editor = null;
		/// <summary>
		/// The HelpRequested event handler for all the Controls in the application
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="hlpevent"></param>
		private static void Global_HelpRequested(object sender, HelpEventArgs hlpevent)
		{
			if( s_editor == null)
			{
				s_editor = new EditHelpString();
				s_editor.CommitHelpString = new CommitHelpString_T( CommitHelpString );
			}
			Control c = sender as Control;
			Form owner_form = c.FindForm();
			Type form_t = owner_form.GetType();
			string assem_name = Path.GetFileName(form_t.Assembly.Location);

			//Popup the Help authoring window only when SHIFT is pressed
			if ( (Native.GetAsyncKeyState( Native.VK_SHIFT) & 0x8000) != 0 )
			{
				s_editor.SetHelp(owner_form,
				                 assem_name, form_t.FullName, c );
			}
		}

		/// <summary>
		/// Key: Lower case assembly name, TODO: maybe not sufficient
		/// Value: ArrayList of FormControl
		/// </summary>
		internal static Hashtable assem_lower_name_VS_ArrayList_of_FormControl = new Hashtable();

		/// <summary>
		/// Send the help string to cache
		/// </summary>
		/// <param name="assembly_name"></param>
		/// <param name="full_class_name"></param>
		/// <param name="control"></param>
		/// <param name="lang_str"></param>
		/// <param name="help_str">If empty, remove the entry</param>
		private static void CommitHelpString(string assembly_name, string full_class_name, Control control,
			string lang_str, string help_str)
		{
			string assem_lower_name = assembly_name.ToLower();
			if( assem_lower_name_VS_ArrayList_of_FormControl.ContainsKey(assem_lower_name) == false )
			{
				assem_lower_name_VS_ArrayList_of_FormControl[assem_lower_name] = new ArrayList();
			}

			ArrayList form_control_arr = assem_lower_name_VS_ArrayList_of_FormControl[assem_lower_name] as ArrayList;
			
			bool found_form = false;
			FormControl target_fc = null;
			foreach(FormControl fc in form_control_arr)
			{
				if( fc.FullFormName != full_class_name )
					continue;

				found_form = true;
				target_fc = fc;
			}

			if( found_form == false)
			{
				target_fc = new FormControl( full_class_name);
				//bugfix: forget the following line to add to list
				form_control_arr.Add(target_fc);
			}
			target_fc.SetHelpStr(control.Name, lang_str, help_str);
			//bugfix: update current help string Only when get culture match.
			//bugfix: help_str => lang_str
			if( lang_str == get_current_ui_lang_str() )
			{
				global_hlp_provider.SetHelpString(control, help_str);
			}
		}

		/// <summary>
		/// Save cached help string to XML file
		/// </summary>
		internal static void ToXml()
		{
			string full_xml_name = Path.Combine(
				Path.GetDirectoryName(Assembly.GetCallingAssembly().Location),
				help_file);

			//TODO: Create useful Xml Comment node
			XmlDocument xml_doc = new XmlDocument();
			//Create Element /HelpStr
			XmlElement root = xml_doc.CreateElement("HelpStr");
			xml_doc.AppendChild(root);

			foreach(DictionaryEntry entry in assem_lower_name_VS_ArrayList_of_FormControl)
			{
				//Create Element /HelpStr/Assembly
				string lower_assem_name = (entry.Key as string);
				XmlElement elem_assem = xml_doc.CreateElement("Assembly");
				elem_assem.SetAttribute("LowerName", lower_assem_name);
				root.AppendChild(elem_assem);

				foreach(FormControl fc in (entry.Value as ArrayList) )
				{
					//Create Element /HelpStr/Assembly/FormControl
					XmlElement elem_form_control = xml_doc.CreateElement( "FormControl");
					elem_form_control.SetAttribute("FullName", fc.FullFormName);
					elem_assem.AppendChild(elem_form_control);

					foreach(DictionaryEntry control_name_VS_lang_help in fc.ControlName_VS_Lang_Help)
					{
						string control_name = control_name_VS_lang_help.Key as string;
						Hashtable lang_help = control_name_VS_lang_help.Value as Hashtable;

						//Create Element /HelpStr/Assembly/FormControl/Control
						XmlElement elem_control = xml_doc.CreateElement("Control");
						elem_control.SetAttribute("Name", control_name);
						elem_form_control.AppendChild(elem_control);

						foreach(DictionaryEntry lang_VS_help in lang_help)
						{
							string lang_str = lang_VS_help.Key as string;
							string help_str = lang_VS_help.Value as string;

							//Create Element /HelpStr/Assembly/FormControl/Control/HelpStr
							XmlElement elem_lang = xml_doc.CreateElement("HelpStr");
							elem_lang.SetAttribute("LowerLangStr", lang_str);
							elem_control.AppendChild(elem_lang);

							//Create Element /HelpStr/Assembly/FormControl/Control/HelpStr/value
							XmlElement elem_value = xml_doc.CreateElement("value");
							elem_value.InnerText = help_str;
							elem_lang.AppendChild(elem_value);
						}
					}
				}
			}
			save_xml(xml_doc, full_xml_name);
		}


		/// <summary>
		/// Load cached help string from XML file
		/// </summary>
		/// <param name="full_xml_fname"></param>
		/// <param name="p_assem_lower_name_VS_ArrayList_of_FormControl"></param>
		internal static void FromXml(string full_xml_fname, Hashtable p_assem_lower_name_VS_ArrayList_of_FormControl)
		{
			Debug.Assert( p_assem_lower_name_VS_ArrayList_of_FormControl != null);

			XmlDocument xml_doc = new XmlDocument();
			xml_doc.Load(full_xml_fname);
			//TODO: Check schema

			foreach( XmlElement assem_elem in xml_doc.SelectNodes("/HelpStr/Assembly"))
			{
				ArrayList list = new ArrayList();
				p_assem_lower_name_VS_ArrayList_of_FormControl[assem_elem.GetAttribute("LowerName")] = list;

				foreach(XmlElement elem_fc in assem_elem.SelectNodes("FormControl") )
				{
					FormControl form_control = new FormControl(elem_fc.GetAttribute("FullName") );
					list.Add(form_control );
					foreach(XmlElement elem_control in elem_fc.SelectNodes("Control"))
					{
						string control_name = elem_control.GetAttribute("Name");
						foreach(XmlElement elem_help in elem_control.SelectNodes("HelpStr") )
						{
							form_control.SetHelpStr(control_name , elem_help.GetAttribute("LowerLangStr"),
								elem_help["value"].InnerText );
						}
					}
				}
			}
		}

		private static void save_xml(XmlDocument doc, string full_xml_fname)
		{
			string tmp_fname = null;
			XmlValidatingReader reader = null;
			Stream schema_stream = null;
			XmlTextWriter writer = null;
			try
			{
				FileAttributes old_fa = FileAttributes.Normal;
				if( File.Exists(full_xml_fname) )
				{
					old_fa = File.GetAttributes( full_xml_fname );
					File.SetAttributes(full_xml_fname, old_fa & ~FileAttributes.ReadOnly );
				}

				tmp_fname = Path.GetTempFileName();

				writer =
					new XmlTextWriter(tmp_fname, new System.Text.UTF8Encoding(false));//no BOM mark
				writer.Formatting = Formatting.Indented;
				writer.Indentation = 2; //����2���ַ�
				doc.Save( writer );
				writer.Close(); writer = null;

				//Check the resulting file by Xml schema
				//If check ok, copy the file
				if( File.Exists(full_xml_fname) ) File.Delete(full_xml_fname);
				File.Move(tmp_fname, full_xml_fname);
				File.SetAttributes(full_xml_fname, old_fa); //Resture the file attributes
				Console.WriteLine("HERE");
			}
			catch(Exception ex)
			{
				Console.WriteLine("HERE Exception" + ex.ToString() );
				Debug.Assert(false, "Temp file: " + tmp_fname + Environment.NewLine + ex.ToString() ) ;
			}
			finally
			{
				if(writer != null) //Write TMP file
					writer.Close();
				if(reader != null) //Xml validate reader <- TMP file
					reader.Close();
				if( schema_stream != null) //Embed xsd file stream
					schema_stream.Close();
				if( File.Exists( tmp_fname) )
					File.Delete(tmp_fname);
			}
		}
		
		/// <summary>
		/// Merge the help specified in parameter into the current.
		/// Conflicted help string should use another_help's
		/// </summary>
		/// <param name="merge">if true, just merge, ignore conflict</param>
		/// <param name="conflict"></param>
		/// <param name="another_help">Help generated by your colleague, same underlying structure as
		/// assem_lower_name_VS_ArrayList_of_FormControl</param>
		internal static void merge_help_str(bool merge, out Hashtable conflict, Hashtable another_help)
		{
			conflict = null;
			try
			{
				merge_help_str_helper(merge, out conflict, another_help);
			}
			catch (Exception ex)
			{
				Debug.Assert(false, "Exception in merge_help_str" + Environment.NewLine + ex.ToString() );
			}
		}

		private static void merge_help_str_helper(bool merge, out Hashtable conflict, Hashtable another_help)
		{
			conflict = null;
			if( another_help == null)
				throw new ArgumentNullException("another_help");

			if( merge == false)
			{
				conflict = new Hashtable();
			}
			foreach(DictionaryEntry entry in another_help)
			{
				string new_assem_name = entry.Key as string;
				ArrayList new_FormControl_vec = entry.Value as ArrayList;
				if( assem_lower_name_VS_ArrayList_of_FormControl.ContainsKey( new_assem_name ) == false)
				{
					if( merge )
						assem_lower_name_VS_ArrayList_of_FormControl.Add(new_assem_name, new_FormControl_vec);
					continue;
				}
				//Search for the matched FormControl
				ArrayList my_FormControl_vec = assem_lower_name_VS_ArrayList_of_FormControl[new_assem_name] as ArrayList;
				foreach(FormControl new_fc in new_FormControl_vec)
				{
					FormControl my_fc = new_fc.find_name_matched(my_FormControl_vec);
					if( my_fc == null)
					{ //I have no such a FormControl
						if( merge ) my_FormControl_vec.Add(new_fc);
						continue;
					}
					//walk through he help strings for all language
					foreach(DictionaryEntry new_ctrl_name_VS_lang_help in new_fc.ControlName_VS_Lang_Help)
					{
						string new_ctrl_name = new_ctrl_name_VS_lang_help.Key as string;
						Hashtable new_lang_VS_help = new_ctrl_name_VS_lang_help.Value as Hashtable;

						if( my_fc.ControlName_VS_Lang_Help.ContainsKey(new_ctrl_name) == false)
						{
							if( merge ) my_fc.ControlName_VS_Lang_Help[new_ctrl_name] = new_lang_VS_help;
							continue;
						}

						Hashtable my_lang_VS_help = my_fc.ControlName_VS_Lang_Help[new_ctrl_name] as Hashtable;
						foreach(DictionaryEntry lang_2_help in new_lang_VS_help)
						{
							//always add or replace even null or empty
							if( merge )
							{
								my_lang_VS_help[lang_2_help.Key] = lang_2_help.Value;
								continue;
							}
							string ori_helpstr = my_lang_VS_help[lang_2_help.Key] as string;
							string new_helpstr = lang_2_help.Value as string;
							if(ori_helpstr == null || ori_helpstr.Length == 0 || ori_helpstr == new_helpstr)
							{//if origin help str is null or empty, or same as new help str, not considered conflict
								continue;
							}

							if( conflict.ContainsKey(new_assem_name) == false )
							{
								conflict[new_assem_name] = new ArrayList();
							}
							ArrayList conflict_FormControl_vec = conflict[new_assem_name] as ArrayList;

							FormControl conflict_fc = new_fc.find_name_matched( conflict_FormControl_vec );
							if( conflict_fc == null)
							{
								conflict_fc = new FormControl(new_fc.FullFormName);
								conflict_FormControl_vec.Add(conflict_fc);
							}
									
							if( conflict_fc.ControlName_VS_Lang_Help.ContainsKey(new_ctrl_name) == false )
							{
								conflict_fc.ControlName_VS_Lang_Help[new_ctrl_name] = new Hashtable();
							}

							Hashtable lang_VS_help = conflict_fc.ControlName_VS_Lang_Help[new_ctrl_name] as Hashtable;
							lang_VS_help[lang_2_help.Key] = lang_2_help.Value;
						}
					}
				}
			}
		}
		/// <summary>
		/// This function will Set DropDownWidth of ComboBox to the width for displaying even the longest item
		/// should be invoked after UI initilized, espically after all the comboBox Items inited.
		/// </summary>
		/// <param name="page">The topmost control, all it's child or grandchild or ... will be set</param>
		public static void InitComboBoxDropDownWidth(Control page)
		{
			try
			{
				if( page is ComboBox)
				{
					InitSingleComboBoxDropDownWidth( (ComboBox)page );
					return;
				}
				foreach(Control c in page.Controls)
				{
					if( c.Controls.Count > 0)
					{
						InitComboBoxDropDownWidth( c ); //recursive
					}
					if(c is ComboBox && ((ComboBox)c).Items.Count > 0)
					{
						InitSingleComboBoxDropDownWidth( (ComboBox)c );
					}
				}
			}
			catch(Exception e)
			{
				Debug.Assert(false, e.ToString() );
			}
		}
		internal static void InitSingleComboBoxDropDownWidth(ComboBox box)
		{
			using(Graphics g = box.CreateGraphics() )
			{
				int width = box.Width;
				for(int i = 0; i < box.Items.Count; i++)
				{
					SizeF size = g.MeasureString( box.GetItemText( box.Items[i] ), box.Font );
					width = Math.Max(width, (int)Math.Floor( size.Width) );
				}
				box.DropDownWidth = width;
				g.Dispose();
			}
		}
	}

	internal class FormControl
	{
		private string m_full_form_name;
		private Hashtable m_control_name_VS_lang_help = new Hashtable();

		/// <summary>
		/// Key: Control name, case sensitive
		/// Value: Hashtable (lang_help)
		/// 
		/// lang_help.Key: lower case lang str, e.g., zh-chs
		/// lang_help.Value: multi-line help string
		/// </summary>
		internal Hashtable ControlName_VS_Lang_Help
		{
			get { return m_control_name_VS_lang_help; }
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="v_this">Item is FormControl</param>
		/// <returns></returns>
		internal FormControl find_name_matched(ArrayList v_this)
		{
			Debug.Assert( v_this != null );
			foreach(FormControl c in v_this)
			{
				if( FullFormName == c.FullFormName)
					return c;
			}
			return null;
		}

		internal string FullFormName
		{
			get { return m_full_form_name; }
		}
		internal FormControl(string fullFormName)
		{
			if( fullFormName == null)
			{
				Debug.Assert(false, "fullFormName = null");
				throw new ArgumentNullException("fullFormName", "fullFormName = null");
			}

			m_full_form_name = fullFormName;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="control_name"></param>
		/// <param name="langString"></param>
		/// <param name="helpString">If Empty, remove the entry</param>
		internal void SetHelpStr(string control_name, string langString, string helpString)
		{
			DefensiveNullChecking(control_name, langString, helpString);

			//The real things
			if( m_control_name_VS_lang_help.ContainsKey(control_name) == false)
			{
				m_control_name_VS_lang_help[control_name] = new Hashtable();
			}
			Hashtable lang_help = m_control_name_VS_lang_help[control_name] as Hashtable;

			if( helpString.Length > 0)
			{
				lang_help[langString] = helpString;
			}
			else
			{
				lang_help.Remove( langString );
			}
		}

		internal string GetHelpStr(string control_name, string langString)
		{
			DefensiveNullChecking(control_name, langString);
			
			if( m_control_name_VS_lang_help.ContainsKey(control_name) == false)
			{
				return null;
			}
			Hashtable lang_help = m_control_name_VS_lang_help[control_name] as Hashtable;
			string lower_lang_str = langString.ToLower();
			if( lang_help.ContainsKey( lower_lang_str ) == false )
			{
				return null;
			}

			Trace.Assert( (lang_help[lower_lang_str] == null) ||
				(lang_help[lower_lang_str] is string), 
				string.Format("Expect type of lang_help is string, actual: {0}",
				lang_help[lower_lang_str].ToString() ));

			return lang_help[lower_lang_str] as string;
		}

		private void DefensiveNullChecking(params object[] all_parameters)
		{
			//TODO: how to get the real parameter name
			foreach(object o in all_parameters )
			{
				if( o == null )
				{
					Debug.Assert(false, "parameter = null");
					throw new ArgumentNullException("parameter", "parameter = null");
				}
				
			}
		}

		public override string ToString()
		{
			Debug.Assert( m_full_form_name != null, "m_full_form_name is null");
			return m_full_form_name;
		}
	}

	class Native
	{
		[DllImport("user32.dll")]
		internal static extern int ReleaseCapture ();

		[DllImport("user32.dll")]
		internal static extern int SendMessage ( 
			IntPtr hwnd,
			int wMsg,
			int wParam,
			int lParam);

		[DllImport("user32.dll")]
		internal static extern int EnableWindow ( 
			int hwnd,
			int fEnable);
		[DllImport("user32.dll")]
		internal static extern int SetForegroundWindow ( 
			int hwnd);

		[DllImport("user32.dll", CallingConvention=CallingConvention.Winapi)]
		internal extern static short GetAsyncKeyState(int vKey);

		internal const int VK_SHIFT = 0x10;
		internal const int WM_NCLBUTTONDOWN = 0xA1;
		internal const int HTCAPTION = 0x2;
	}

	internal delegate void CommitHelpString_T(string assembly_name, string full_class_name, Control control,
		string lang_str, string help_str);


}

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

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

License

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


Written By
Software Developer
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions