Click here to Skip to main content
15,886,806 members
Articles / Desktop Programming / Windows Forms

C# WinForms Application Full Integration with HTMLHelp ( .chm ) - Help Topics, Context Sensitive Help, and Tooltips

Rate me:
Please Sign up or sign in to vote.
4.67/5 (12 votes)
4 May 2011CPOL5 min read 64K   2.2K   48  
Use HTMLHelp (.chm) to display help topics, context sensitive help and tooltips in C# Winform application
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WinHelpLib
{


    public class WinHelpEx
    {

        static int idString = 1;
        static StreamWriter textStreamWriter = null;
        public static void AttachOutput(Stream sOutput)
        {
            textStreamWriter = new StreamWriter(sOutput);
        }

        public static void AttachOutput(Stream sOutput, int idS)
        {
            textStreamWriter = new StreamWriter(sOutput);
            idString = idS;
        }


        public static void ReleaseOutput()
        {
            textStreamWriter.Close();
            textStreamWriter = null;
        }

        Dictionary<String, uint> s_alias_id = new Dictionary<string,uint>();
        void LoadAliasDictionary(Stream isDic)
        {
            try
            {

                StreamReader textStreamReader = new StreamReader(isDic);

                String sLine = "";
                while (!textStreamReader.EndOfStream)
                {
                    sLine = textStreamReader.ReadLine();
                    string[] sDefine = sLine.Split(new char[]{' ','\t'},StringSplitOptions.RemoveEmptyEntries);
                    if (sDefine.Length == 3 && sDefine[0] == "#define")
                    {
                        s_alias_id[sDefine[1]] = Convert.ToUInt32(sDefine[2]);
                    }
                }
                textStreamReader.Close();
            }
            catch
            {
            }
        }


        Dictionary<uint, String> s_alias_tooltip = new Dictionary<uint, String>();
        void LoadTooltipDictionary(string sName)
        {
            try
            {
                IStorageEx iSt = IDocFileEx.Open(m_hp.HelpNamespace);

                if (iSt != null)
                {

                    IStreamEx iStream = iSt.OpenStream(sName);

                    if (iStream != null)
                    {

                        StreamReader textStreamReader = new StreamReader(iStream);

                        uint uiSID = 0;
                        String sText = "";


                        String sLine = "";
                        while (!textStreamReader.EndOfStream)
                        {
                            sLine = textStreamReader.ReadLine();
                            string[] sDefine = sLine.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                            if (sDefine.Length == 2 && sDefine[0] == ".topic")
                            {
                                if (uiSID != 0)
                                {
                                    s_alias_tooltip[uiSID] = sText.Trim('\n');
                                }
                                uiSID = Convert.ToUInt32(sDefine[1]);
                                sText = "";
                            }
                            else
                            {
                                sText += "\n" + sLine;
                            }
                        }

                        if (uiSID != 0)
                        {
                            s_alias_tooltip[uiSID] = sText.Trim('\n');
                        }

                        textStreamReader.Close();

                        m_bNoTooltips = false;
                        return;
                    }
                }
            }
            catch
            {
            }

            m_bNoTooltips = true;

        }

        HTMLHelpEx m_htmlHelp;
        ToolTip m_tt;
        HelpProvider m_hp;

        bool m_bNoTooltips = false;
        bool m_bNoCSHelp = false;

        public void Load(string sChmPath,Stream sAliasIDH,string sCSStreamName,string sTTStreamName)
        {
            m_htmlHelp = new HTMLHelpEx(sChmPath, sCSStreamName);
            m_tt = new ToolTip();
            m_hp = new HelpProvider();
            m_hp.HelpNamespace = sChmPath;

            m_bNoCSHelp = String.IsNullOrEmpty(sCSStreamName);
            m_bNoTooltips = String.IsNullOrEmpty(sTTStreamName);

            // need this for the topics , cshelp and tooltips
            LoadAliasDictionary(sAliasIDH);

            if (!m_bNoTooltips)
                LoadTooltipDictionary(sTTStreamName);

        }

        //called back the form and return false if we dont want to set help for this control
        public enum HELP_CTRL_USE
        {
            USE_SUB,    //use the control and subcontrols
            USE_NO_SUB, //use the control but don't use the subcontrols
            NO_USE_NO_SUB,//don't use control and subcontrols
            NO_USE_SUB//don't use control but use subcontrols
        }
        //called back the form and return non null if we want to overwrite the default control name 
        public delegate HELP_CTRL_USE GetControlNameDlgt(Control ctrl, ref String sName);
        String GetControlName(Control baseCtrl, Control ctrl, GetControlNameDlgt getCtrlName)
        {
            if (ctrl == baseCtrl.Parent)
            {
                return "";
            }

            String sParentName = "";

            if (getCtrlName != null)
            {
                String strName = "";
                HELP_CTRL_USE hcu = getCtrlName(ctrl, ref strName);
                if (hcu == HELP_CTRL_USE.USE_SUB)
                {
                    if (String.IsNullOrEmpty(strName))
                    {
                        strName = ctrl.Name; 
                    }

                    sParentName = GetControlName(baseCtrl,ctrl.Parent, getCtrlName);
                    if (String.IsNullOrEmpty(sParentName))
                    {
                        return strName;
                    }
                    return sParentName + "." + strName;

                }
                else if (hcu == HELP_CTRL_USE.USE_NO_SUB)
                {
                    if (String.IsNullOrEmpty(strName))
                    {
                        strName = ctrl.Name; 
                    }
                    return strName;
                }
                else if (hcu == HELP_CTRL_USE.NO_USE_SUB)
                {
                    return GetControlName(baseCtrl, ctrl.Parent, getCtrlName);
                }
                else if (hcu == HELP_CTRL_USE.NO_USE_NO_SUB)
                {
                }
                return "";
            }

            sParentName = GetControlName(baseCtrl, ctrl.Parent, getCtrlName);
            if (String.IsNullOrEmpty(sParentName))
            {
                return ctrl.Name;
            }

            return sParentName + "." + ctrl.Name;
        }

        public delegate HELP_CTRL_USE IsControlUsedDlgt(Control ctrl);
        HELP_CTRL_USE IsControlUsed(Control ctrl, IsControlUsedDlgt isCtrlUsed)
        {
            if (isCtrlUsed == null)
            {
                return HELP_CTRL_USE.USE_SUB;
            }
            return isCtrlUsed(ctrl);
        }
        public delegate Boolean IsCSHelpDlgt(Control ctrl);

        void SetHelp(
            Control ctrlBase,
            Control ctrl,
            GetControlNameDlgt GetCtrlName,
            bool bIsCSHelp
        )
        {
            String ctrlName = GetControlName(ctrlBase, ctrl, GetCtrlName);

            if (textStreamWriter != null)
            {

                if (ctrl is Form)
                {
                    textStreamWriter.WriteLine("/////////////////////////////////");
                    textStreamWriter.WriteLine("// " + ctrlName);
                    textStreamWriter.WriteLine("/////////////////////////////////");
                }

                textStreamWriter.WriteLine("#define " + ctrlName + " " + idString.ToString());
                idString++;
            }
            else
            {
                if (bIsCSHelp)
                {
                    ctrl.HelpRequested += delegate(object sender, HelpEventArgs args)
                    {
                        HelpRequested(ctrl,ctrlName);
                    };
                }
                else
                {
                    if (s_alias_id.ContainsKey(ctrlName))
                    {
                        m_hp.SetHelpKeyword(ctrl, s_alias_id[ctrlName].ToString());
                        m_hp.SetHelpNavigator(ctrl, HelpNavigator.TopicId);
                        m_hp.SetShowHelp(ctrl, true);
                    }
                }
            }
        }

        void SetTooltip(
            Control ctrlBase,
            Control ctrl,
            GetControlNameDlgt GetCtrlTTName
        )
        {
            String frmName = GetControlName(ctrlBase, ctrl, GetCtrlTTName) + ".TT";
            if (textStreamWriter != null)
            {
                textStreamWriter.WriteLine("#define " + frmName + " " + idString.ToString());
                idString++;
            }
            else
            {
                if (s_alias_id.ContainsKey(frmName))
                {
                    if (s_alias_tooltip.ContainsKey(s_alias_id[frmName]))
                    {
                        m_tt.SetToolTip(ctrl, s_alias_tooltip[s_alias_id[frmName]]);
                    }
                }
            }
        }



        public void AttachForm(
            Control ctrlBase,
            Form frm,
            bool putHelpButton,
            IsControlUsedDlgt IsCtrlUsed,
            GetControlNameDlgt GetCtrlName,
            IsCSHelpDlgt IsCSHelp,
            IsControlUsedDlgt IsCtrlTTUsed,
            GetControlNameDlgt GetCtrlTTName
        )
        {

            if (ctrlBase == null)
            {
                ctrlBase = frm;
            }

            if (putHelpButton)
            {
                frm.MinimizeBox = false;
                frm.MaximizeBox = false;
                frm.HelpButton = true;
            }

            HELP_CTRL_USE hcuUsage = IsControlUsed(frm,IsCtrlUsed);
            if(
                !m_bNoCSHelp &&
                (hcuUsage == HELP_CTRL_USE.USE_NO_SUB || hcuUsage == HELP_CTRL_USE.USE_SUB)
            )
            {
                // we can force form to have CS Help if we set it explicitly through IsCSHelp
                SetHelp(
                    ctrlBase,
                    frm,
                    GetCtrlName,
                    (IsCSHelp != null && IsCSHelp(frm))
                );

            }

            HELP_CTRL_USE hcuTTUsage = IsControlUsed(frm, IsCtrlTTUsed);
            if (IsCtrlTTUsed != null)
            {
                // normally form should not have a tooltips but if we want to force it we can through IsCtrlTTUsed implementation
                if (
                    !m_bNoTooltips &&
                    (hcuTTUsage == HELP_CTRL_USE.USE_NO_SUB || hcuTTUsage == HELP_CTRL_USE.USE_SUB)
                )
                {

                    SetTooltip(
                        ctrlBase,
                        frm,
                        GetCtrlTTName
                    );

                }
            }

            if(
                (
                    !m_bNoCSHelp &&
                    (hcuUsage == HELP_CTRL_USE.NO_USE_SUB || hcuUsage == HELP_CTRL_USE.USE_SUB)
                )
                ||
                (
                    !m_bNoTooltips &&
                    (hcuTTUsage == HELP_CTRL_USE.NO_USE_SUB || hcuTTUsage == HELP_CTRL_USE.USE_SUB)
                )
            )
            {
                foreach (Control c in frm.Controls)
                {
                    AttachControl(
                        ctrlBase,
                        c,
                        IsCtrlUsed,
                        GetCtrlName,
                        IsCSHelp,
                        IsCtrlTTUsed,
                        GetCtrlTTName
                    );
                }
            }
        }

        public void AttachControl(
            Control ctrlBase,
            Control ctrl,
            IsControlUsedDlgt IsCtrlUsed,
            GetControlNameDlgt GetCtrlName,
            IsCSHelpDlgt IsCSHelp,
            IsControlUsedDlgt IsCtrlTTUsed,
            GetControlNameDlgt GetCtrlTTName

        )
        {

            if (ctrlBase == null)
            {
                ctrl = ctrlBase;
            }

            HELP_CTRL_USE hcuUsage = IsControlUsed(ctrl, IsCtrlUsed);

            if (
                !m_bNoCSHelp &&
                (hcuUsage == HELP_CTRL_USE.USE_NO_SUB || hcuUsage == HELP_CTRL_USE.USE_SUB)
            )
            {
                SetHelp(
                    ctrlBase,
                    ctrl,
                    GetCtrlName,
                    (IsCSHelp == null || IsCSHelp(ctrl))
                );
            }

            HELP_CTRL_USE hcuTTUsage = IsControlUsed(ctrl, IsCtrlTTUsed);
            if (
                !m_bNoTooltips &&
                (hcuTTUsage == HELP_CTRL_USE.USE_NO_SUB || hcuTTUsage == HELP_CTRL_USE.USE_SUB)
            )
            {
                SetTooltip(
                    ctrlBase,
                    ctrl,
                    GetCtrlTTName
                );
            }



            if (
                (
                    !m_bNoCSHelp &&
                    (hcuUsage == HELP_CTRL_USE.NO_USE_SUB || hcuUsage == HELP_CTRL_USE.USE_SUB)
                )
                ||
                (
                    !m_bNoTooltips &&
                    (hcuTTUsage == HELP_CTRL_USE.NO_USE_SUB || hcuTTUsage == HELP_CTRL_USE.USE_SUB)
                )
            )
            {
                foreach (Control c in ctrl.Controls)
                {
                    AttachControl(
                        ctrlBase,
                        c,
                        IsCtrlUsed,
                        GetCtrlName,
                        IsCSHelp,
                        IsCtrlTTUsed,
                        GetCtrlTTName
                    );
                }
            }
        }

        void HelpRequested(Control ctrl,string sCtrlName)
        {

            if (!s_alias_id.ContainsKey(sCtrlName))
                return;

            m_htmlHelp.ShowContextHelp(s_alias_id[sCtrlName], ctrl);

        }

        public void ShowHelp(Control ctrl, HelpNavigator hn, object oKeyword)
        {
            m_htmlHelp.ShowHelp(ctrl, hn, oKeyword);
        }


        void AddStorage(IStorageEx iSt,TreeNode ptn)
        {
            iSt.EnumStart();

            string sName = "";
            STGTY sType = 0;

            while (iSt.EnumNext(ref sName,ref sType))
            {
                TreeNode tn = ptn.Nodes.Add(sName);
                if (sType == STGTY.STGTY_STORAGE)
                {
                    IStorageEx iChSt = iSt.OpenStorage(sName);
                    AddStorage(iChSt, tn);
                }

            }

        }

        public void TestITSS(TreeView tv)
        {
            IStorageEx iSt = IDocFileEx.Open(m_hp.HelpNamespace);

            if (iSt != null)
            {
                TreeNode tn = tv.Nodes.Add("CHM");
                AddStorage(iSt, tn);
            }
        }

    }





}

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 (Senior)
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions