Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Remoting Management Console

Rate me:
Please Sign up or sign in to vote.
4.96/5 (68 votes)
11 Apr 200310 min read 231.5K   6.6K   169  
This is a MMC Snap-in to manage a remoting host process and its configuration file. Like the COM+ catalog, the Remoting Management Console will create and administrate the host process to publish your remoting objects.
//-------------------------------------------------------------
// CPropPage.cs
//
// This file defines the base class that all property sheet pages
// must derive from.
//-------------------------------------------------------------

// the method to use for mapping between pixels and dialog units
#define METHOD4


using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace Ironring.Management.MMC
{

    /// <summary>
    /// Wrapper for the MMC Property pages.  Requirs a UserControl type provided 
    /// to implement the PropertyPage behavior
    /// </summary>
    public class CPropPage
    {

        /// <summary>
        /// the type of control to activate
        /// </summary>
        protected Type m_ControlType;     

        /// <summary>
        /// the instance of the control once activated 
        /// </summary>
        protected UserControl m_Control = null;        

        /// <summary>
        /// Title to display in property sheet tab 
        /// </summary>
        protected string m_sTitle;         

        /// <summary>
        /// Parent window - the actual Win32 property page handle.
        /// The UserControl will be an immediate child of this window
        /// </summary>
        protected IntPtr m_hWnd = IntPtr.Zero;            
        /// <summary>
        /// Icon to display
        /// </summary>
        protected Icon m_Icon = null;            

        /// <summary>
        /// WindProc for the property page
        /// </summary>
        protected DialogProc m_dlgProc;

        /// <summary>
        /// The node the property page refers to
        /// </summary>
        protected BaseNode m_Node = null;    
 
        /// <summary>
        /// The dialog template for this property page
        /// </summary>
        protected IntPtr m_pDlgTemplate;


        ///////////////////////////////////////////////////////////////
        ///
        /// Implementation
        ///
 
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="title"></param>
        public CPropPage(string title)
        {
            m_sTitle = title;
            m_dlgProc = new DialogProc(PropPageDialogProc);
        }

        /// <summary>
        /// Set the type of User Control to serve as the property page guts
        /// </summary>
        public Type ControlType
        {
            get { return m_ControlType; } 
            set { m_ControlType = value; }
        }

        /// <summary>
        /// Title
        /// </summary>
        public string Title
        {
            get { return m_sTitle; }
            set { m_sTitle = value; } 
        }

        /// <summary>
        /// Icon
        /// </summary>
        public Icon Icon
        {
            get { return m_Icon; }
            set { m_Icon = value; } 
        }

        /// <summary>
        /// Create the property page resource and return an IntPtr
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public IntPtr Create(BaseNode node)
        {
            m_Node = node;
               
            PROPSHEETPAGE psp;

            psp = new PROPSHEETPAGE();
            psp.dwSize = 48;
            psp.hInstance = IntPtr.Zero;

            //        m_hIcon = node.IconHandle;

            psp.dwFlags = (uint)PSP.DEFAULT | (uint)PSP.DLGINDIRECT;  // PSP.USECALLBACK | 

            // We're using just a plain resource file as a "placeholder" for our .NET Framework Classes
            // placed controls
            psp.pResource = GetDialogTemplate();
            psp.lParam = IntPtr.Zero;  
            psp.pfnDlgProc = m_dlgProc;

            // See if our property page uses a icon
            if (Icon != null)
            {
                psp.hIcon = Icon.Handle;
                psp.dwFlags |= (uint)PSP.USEHICON;
            }
                        
            // See if our property page uses a title
            if (Title != null)
            {
                psp.pszTitle = Title;
                psp.dwFlags |= (uint)PSP.USETITLE;
            }

            return CreatePropertySheetPage(ref psp);
        }

        /// <summary>
        /// Create a DIALOGTEMPLATE resource to give to MMC.  It must be initialized 
        /// to the correct dimensions to host the UserControl.
        /// </summary>
        /// <returns></returns>
        protected IntPtr GetDialogTemplate()
        {
            // If we're already created a template, don't bother doing it again
            if (m_pDlgTemplate != IntPtr.Zero)
                return m_pDlgTemplate;
        
            DLGTEMPLATE dlg = new DLGTEMPLATE();

            // try to synth the template from the user control properties 
            // so the propertysheet owned by MMC can size itself properly

            Font fnt = MainControl.Font;
            
            /////////////////////////////////////////////////////////////////
            // method #1 use a string to compute some avaerages 

#if METHOD1

            UserControl userControl = (UserControl)Activator.CreateInstance(ControlType);
            Graphics g = userControl.CreateGraphics();


            const string baseline = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                    + "abcdefghijklmnopqrstuvwxyz"
                                    + "0123456789"
                                    + "~+=`][{})(*&^%$#@!_-|"
                                    + @"\""";

            const string baseline = " abcdefghijklmnopqrstuvwxyz";

            SizeF sz = g.MeasureString(baseline, fnt);
            int OffsetX = (int)(sz.Width / baseline.Length + 1);
            int OffsetY = (int)(fnt.GetHeight(g) + 1);

            // devine the prop page height and width in dlg units
            // based on the user control's dimensions

            int fx = userControl.Width;
            int fy = userControl.Height;

            dlg.cx = (short)(fx * 4 / OffsetX);
            dlg.cy = (short)(fy * 8 / OffsetY);

            userControl.Dispose();

#endif
            /////////////////////////////////////////////////////////////////

            /////////////////////////////////////////////////////////////////
            // method #2 using text metrics
    #if METHOD2

            UserControl userControl = (UserControl)Activator.CreateInstance(ControlType);
            Graphics g = userControl.CreateGraphics();

            TEXTMETRIC tm = new TEXTMETRIC();
            GetTextMetrics(g.GetHdc(), ref tm);
            
            float OffsetX = tm.tmAveCharWidth;
            float OffsetY = tm.tmHeight;

            // devine the prop page height and width in dlg units
            // based on the user control's dimensions

            float fx = (float )userControl.Width;
            float fy = (float )userControl.Height;

            dlg.cx = (short)(fx * 4 / OffsetX);
            dlg.cy = (short)(fy * 8 / OffsetY);


            userControl.Dispose();

    #endif    
            /////////////////////////////////////////////////////////////////

    #if METHOD3
            
            /////////////////////////////////////////////////////////////////
            // method #3 using system wide dialog units

            int nBaseUnits = GetDialogBaseUnits();

            int OffsetX = 0xFFFF & nBaseUnits;
            int OffsetY = nBaseUnits >> 16;

            // devine the prop page height and width in dlg units
            // based on the user control's dimensions
            dlg.cx = (short)(MainControl.Width * 4 / OffsetX);
            dlg.cy = (short)(MainControl.Height * 8 / OffsetY);

            /////////////////////////////////////////////////////////////////
    #endif

    #if METHOD4
            /////////////////////////////////////////////////////////////////
            // method #4 A variation on #2 with hard coded magic numbers
            // I got these from experiment - this really freaks me out
            // I need to understand this better to defend it but it 
            // works for now (I hate that).
            
            int OffsetX = 6;
            int OffsetY = 13;

            dlg.cx = (short)(MainControl.Width * 4 / OffsetX);
            dlg.cy = (short)(MainControl.Height * 8 / OffsetY);

            /////////////////////////////////////////////////////////////////
    #endif

            // Put in a the standard font 
            dlg.style = (uint)DS.SETFONT;
            dlg.wFontPointSize = (short)fnt.Size;
 
            // write the font name into the buffer
            MemoryStream stream = new MemoryStream(64);
            Encoding ue = new UnicodeEncoding();
            BinaryWriter writer = new BinaryWriter(stream, ue);
            writer.Write(fnt.Name);

            int nSize = Marshal.SizeOf(typeof(DLGTEMPLATE));
            m_pDlgTemplate = Marshal.AllocHGlobal(nSize + (int)stream.Length);
            Marshal.StructureToPtr(dlg, m_pDlgTemplate, false);
            
            // Now copy the string into the IntPtr
            Marshal.Copy(stream.GetBuffer(), 0, (IntPtr)((Int64)m_pDlgTemplate + nSize), (int)stream.Length);
            return m_pDlgTemplate;
        }

        /// <summary>
        /// The WindProc for the PropertyPage handles avtivation and PropertySheet 
        /// Messeges but mostly defers to the UserControl.
        /// </summary>
        /// <param name="hwndDlg"></param>
        /// <param name="msg"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        public bool PropPageDialogProc(IntPtr hwndDlg, uint msg, IntPtr wParam, IntPtr lParam)
        {
            try
            {
                WM m = (WM)msg;
                //System.Diagnostics.Debug.WriteLine("[" + hwndDlg.ToString() + "]" + " PP_MSG: " + m.ToString() + " wParam: " + wParam.ToString() + " lParam: " + lParam.ToString());
                switch (m)
                {
                    case WM.INITDIALOG:
                    {
                        m_hWnd = hwndDlg;

                        // Set up our parent managed control first
                        SetParent(MainControl.Handle, m_hWnd);

                        return true;
                    }
                    case WM.DESTROY:
                    {
                        // tell MMC that we're done with the property sheet 

                        //                if (m_Node != null)
                        //              {
                        //                m_Node.FreePropertySheetNotifyHandle();
                        //              return true;
                        //         }
                        // If we don't belong to a specific node, then we can't handle
                        // this message
                        return false;

                    }
                    case WM.NOTIFY:
                    {

                        // lParam really is a pointer to a NMHDR structure....
                        NMHDR nm = new NMHDR();
                        nm = (NMHDR)Marshal.PtrToStructure(lParam, nm.GetType());

                        // We're about to lose focus of this property page. Make sure the data
                        // is valid before we allow that
                        if (nm.code == PSN.KILLACTIVE)
                        {
                            if (!ValidateData())
                            {
                                // The data on the page had errors
                                SetWindowLong(hwndDlg, 0, 1);
                            }
                            return true;
                        }
                        
                            // If we're being told to apply changes made in the property pages....
                        else if (nm.code == PSN.APPLY)
                        {

                            // First, call a validate on the current page
                            if (ValidateData())
                                // 'Apply' this data
                                ApplyData();
                                // There were errors on this page...
                            else
                                // Set the appropriate return code here.
                                SetWindowLong(hwndDlg, 0, (uint)PSNRET.INVALID_NOCHANGEPAGE);
                            return true;
                        }
                        break;
                    }
                    default:
                    {
                        // We'll let the default windows message handler handle the rest of
                        // the messages
                        return false;
                    }
                }
            }
            catch(Exception e)
            {
                System.Diagnostics.Debug.WriteLine("PropPage Proc Exception - " + e.ToString());
                throw e;
            }

            return false;
        }

        /// <summary>
        /// This function will turn on the apply button by sending a message to the parent window
        /// </summary>
        public void ActivateApply()
        {
            SendMessage(GetParent(m_hWnd), (uint)PSM.CHANGED, (uint)m_hWnd, 0);
        }


        /// <summary>
        /// This function gets called when someone clicks OK, APPLY,
        /// Finish, Next, or tries to move to a different property
        /// page. It should return 'true' if everything is ok,
        /// or false if things are not ok
        /// </summary>
        /// <returns></returns>
        public virtual bool ValidateData()
        {
            return MainControl.Validate();
        }

        /// <summary>
        /// This function gets called when somebody clicks 
        /// OK, APPLY, or FINISH on our property page/wizard.
        /// It should return true if everything is ok, or false
        /// if things are not ok.
        /// </summary>
        /// <returns></returns>
        public virtual bool ApplyData()
        {
            return true;
        }

        
        /// <summary>
        /// Return our parent HWND
        /// </summary>
        protected IntPtr hWnd
        {
            get { return m_hWnd; }
        }
         
        /// <summary>
        /// Called to lazy create the user control for this page
        /// </summary>
        protected UserControl MainControl 
        {
            get 
            { 
                try
                {
					if (m_Control == null)
					{
						m_Control = (UserControl)Activator.CreateInstance(ControlType);
						// check if the usercontrol implements ISnapinLink
						// if so provide a back reference to the base snapin.
						ISnapinLink snapinLink = m_Control as ISnapinLink;
						if(snapinLink != null)
							snapinLink.ContextNode = m_Node;
					}
                }
                catch(Exception e)
                {
                    System.Diagnostics.Debug.WriteLine("PropertyPage Exception - " + e.ToString());
                    throw new SnapinException ("Failed to create user control", e);
                }
                return m_Control;
            }
        }

        ////////////////////////////////////////////////////////////////////////////////
        /// P/Invoke methods to get at Win32 
        /// 
            
        /// <summary>
        /// Used to place the Usercontrol in the Windows heirarchy - under the 
        /// MMC Property page window
        /// </summary>
        [DllImport("user32.dll")]
        protected static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        /// <summary>
        /// Used to get the property sheet window
        /// </summary>
        [DllImport("user32.dll")]
        protected static extern IntPtr GetParent(IntPtr hWnd);  

        /// <summary>
        /// Used to communicate with the property sheet window
        /// </summary>
        [DllImport("user32.dll")]
        protected static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

        /// <summary>
        /// Used to communicate with the property sheet
        /// </summary>
        [DllImport("user32.dll")]
        protected static extern int SetWindowLong(IntPtr hWnd, uint a, uint b);

        /// <summary>
        /// The underlying Win32 API to create a property page
        /// </summary>
        [DllImport("comctl32.dll")]
        protected static extern IntPtr CreatePropertySheetPage(ref PROPSHEETPAGE psp);

        /// <summary>
        /// Used in one scheme to dimension the in memory DIALOGTEMPLATE resource
        /// </summary>
        [DllImport("user32.dll")]
        protected static extern int GetDialogBaseUnits();

        /// <summary>
        /// Used in one scheme to dimension the in memory DIALOGTEMPLATE resource
        /// </summary>
        [DllImport("Gdi32.dll")]
        protected static extern int GetTextMetrics(IntPtr hDC, ref TEXTMETRIC lptm);
    }
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


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

Comments and Discussions