home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples.exe / mmc / CNode.cs < prev    next >
Encoding:
Text File  |  2000-06-23  |  19.9 KB  |  601 lines

  1. //-------------------------------------------------------------
  2. // CNode.cs
  3. //
  4. // This class represents individual nodes in the snapin.
  5. // It is responsible for virtually all aspects involving individual
  6. // nodes, ranging from adding children to displaying property pages.
  7. //-------------------------------------------------------------
  8.  
  9. using System;
  10. using System.Runtime.InteropServices;
  11.  
  12. namespace Microsoft.SampleMMC
  13. {
  14. public class CNode
  15. {
  16.     private String              m_sGuid;                 // The guid for this Node
  17.     private String              m_sHelpSection;          // The link into the help file for this node
  18.     private CNode[]             m_naChildren;            // The children this node has
  19.     private String              m_sDisplayName;          // The display name
  20.     private int                 m_iCookie;               // The unique identifier for this node
  21.     private int                 m_iHScopeItem;           // MMC's unique identifier for this object 
  22.     public  Object              m_oResults;              // The items that will be displayed in the result pane
  23.     private int                 m_iResultNum;            // If there are multiple results, the result to use 
  24.     private int                 m_hIcon;                 // The icon for this node
  25.     private int                 m_iParentHScopeItem;     // MMC's unique identifier for the parent
  26.     private int                 m_hPropertyPageRouter;   // MMC's handle for handling a Property sheet
  27.     private IPropSheetPage[]    m_aPropSheetPage;        // The property pages for this item
  28.     private DialogProc          m_MyDProc;               // The dialog callback
  29.     private PropSheetPageProc   m_MyPProc;               // The property page callback
  30.     private int                 m_hModule;               // A handle to this module
  31.  
  32.     //-------------------------------------------------
  33.     // CNode - Constructor
  34.     //
  35.     // This transfers data for the node information structure
  36.     // into the class and loads the node's icon.
  37.     //-------------------------------------------------
  38.     public CNode(int initCookie, NodeInfo initNode)
  39.     {
  40.         m_iCookie = initCookie;
  41.  
  42.         // Pull all the info out of the structure
  43.         m_sGuid = initNode.sGuid;
  44.         m_sHelpSection = initNode.sHelpLink;
  45.         m_sDisplayName = initNode.sName;
  46.         m_oResults = initNode.oResults;
  47.         m_aPropSheetPage = initNode.ppaPages;
  48.         m_hModule = Marshal.GetHINSTANCE(this.GetType().Module);
  49.  
  50.         if (initNode.sIcon != null)
  51.             m_hIcon = LoadIcon(m_hModule, initNode.sIcon);       
  52.         else
  53.             m_hIcon = 0;
  54.  
  55.         m_iResultNum = 0;
  56.         m_iHScopeItem = 0;
  57.     }// CNode
  58.  
  59.     //-------------------------------------------------
  60.     // ~CNode - Destructor
  61.     //
  62.     // The destructor destroys the icon associated with
  63.     // this node
  64.     //-------------------------------------------------
  65.     ~CNode()
  66.     {
  67.         if (m_hIcon != 0)    
  68.             DestroyIcon(m_hIcon);
  69.     }// ~CNode
  70.  
  71.     //-------------------------------------------------
  72.     // The following methods allow access to the node's
  73.     // private data members.
  74.     //-------------------------------------------------
  75.     public bool HavePropertyPages
  76.     {
  77.         get
  78.         {
  79.             return (m_aPropSheetPage != null);
  80.         }
  81.     }// HavePropertyPages
  82.  
  83.     public int ResultNum
  84.     {
  85.         get
  86.         {
  87.             return m_iResultNum;
  88.         }
  89.         set
  90.         {
  91.             m_iResultNum = value;
  92.         }
  93.     }// ResultNum
  94.  
  95.     public int ParentHScopeItem
  96.     {
  97.         get
  98.         {
  99.             return m_iParentHScopeItem;
  100.         }
  101.     }// ParentHScopeItem
  102.     
  103.     public int IconHandle
  104.     {
  105.         get
  106.         {
  107.             return m_hIcon;
  108.         }
  109.     }// IconHandle
  110.  
  111.     // This function will only return a result if the
  112.     // result pane view is going to be an HTML page. All
  113.     // other views are handled internally by the node.
  114.     public String Result
  115.     {
  116.         get
  117.         {
  118.             if (m_oResults is String[])
  119.                 return ((String[])m_oResults)[m_iResultNum];
  120.             else
  121.                 return null;
  122.         }
  123.     }// Result
  124.  
  125.     public int HScopeItem
  126.     {
  127.         get
  128.         {
  129.             return m_iHScopeItem;
  130.         }
  131.         set
  132.         {
  133.             m_iHScopeItem = value;
  134.         }
  135.     }// HScopeItem
  136.  
  137.     public int Cookie
  138.     {
  139.         get
  140.         {
  141.             return m_iCookie;
  142.         }
  143.         set
  144.         {
  145.             m_iCookie = value;
  146.         }
  147.    }// Cookie
  148.  
  149.     
  150.     public String DisplayName
  151.     {
  152.         get
  153.         {
  154.             return m_sDisplayName;
  155.         }
  156.         set
  157.         {
  158.             m_sDisplayName = value;
  159.         }
  160.     }// DisplayName
  161.  
  162.     // This returns the displayname in a byte array, which
  163.     // is required by IDataObject to send the name over a stream
  164.     public byte[] bDisplayName
  165.     {
  166.         get
  167.         {
  168.             return StringToByteArray(m_sDisplayName);
  169.         }
  170.     }// bDisplayName
  171.  
  172.  
  173.     public String Guid
  174.     {
  175.         get
  176.         {
  177.             return m_sGuid;
  178.         }
  179.         set
  180.         {
  181.             m_sGuid = value;
  182.         }
  183.     }// Guid
  184.  
  185.     // This returns the guid in a byte array, which
  186.     // is required by IDataObject to send the guid over a stream
  187.     public byte[] bGuid
  188.     {
  189.         get
  190.         {
  191.             return StringToByteArray(m_sGuid);
  192.         }
  193.     }// bGuid
  194.     
  195.  
  196.     public String HelpSection
  197.     {
  198.         get
  199.         {
  200.             return m_sHelpSection;
  201.         }
  202.         set
  203.         {
  204.             m_sHelpSection = value;
  205.         }
  206.     }// HelpSection
  207.  
  208.     public int NumChildren
  209.     {
  210.         get
  211.         {
  212.            if (m_naChildren == null)
  213.             return 0;
  214.            else 
  215.             return m_naChildren.Length;
  216.         }
  217.     }// NumChildren
  218.  
  219.     public CNode[] Child
  220.     {
  221.         get
  222.         {
  223.             return m_naChildren;
  224.         }
  225.     }// Child
  226.  
  227.     
  228.     //-------------------------------------------------
  229.     // AddChild
  230.     //
  231.     // This function is called whenever we want to add
  232.     // a child node to this node
  233.     //-------------------------------------------------
  234.     public void AddChild(ref CNode NewChild)
  235.     {
  236.         int i;
  237.  
  238.         CNode[] temp = new CNode[NumChildren + 1];
  239.  
  240.         for(i=0; i<NumChildren; i++)
  241.             temp[i] = m_naChildren[i];
  242.  
  243.         // Now add the new element
  244.         temp[i] = NewChild;
  245.  
  246.         // Now assign this new array to the internal array
  247.         m_naChildren = temp;
  248.     }// AddChild
  249.  
  250.     //-------------------------------------------------
  251.     // InsertChildren
  252.     //
  253.     // This function sends all the node's children
  254.     // information to MMC
  255.     //-------------------------------------------------
  256.     public void InsertChildren(ref IConsoleNameSpace2 cns, int thisHScopeItem)
  257.     {
  258.  
  259.         // In the case of the first node, it won't have its HScopeItem field set yet.
  260.         // We'll set that now
  261.         m_iHScopeItem = thisHScopeItem;
  262.  
  263.         // Notice we're using SCOPEDATAITEM (instead of SCOPEDATAITEM2) because the 
  264.         // str field needs to have a number placed in it so we may initiate a callback
  265.        
  266.         SCOPEDATAITEM sdi = new SCOPEDATAITEM();
  267.         
  268.         int numChildren = NumChildren;
  269.  
  270.         for(int i=0; i<numChildren; i++)
  271.         {
  272.         
  273.             sdi.mask = SDI.STR       |   
  274.                        SDI.PARAM     |   
  275.                        SDI.PARENT    |
  276.                        SDI.IMAGE     |
  277.                        SDI.OPENIMAGE |
  278.                        SDI.CHILDREN;
  279.  
  280.             // The image index is going to be the same as the cookie value
  281.             sdi.nImage      = Child[i].Cookie;
  282.             // The open image is the same as the closed image
  283.             sdi.nOpenImage  = Child[i].Cookie;
  284.             sdi.relativeID  = thisHScopeItem;
  285.             // We set displayname to -1 to initiate a callback for the string
  286.             // (We need to do it this way... it's an MMCism)
  287.             sdi.displayname = -1;
  288.             
  289.             sdi.lParam      = Child[i].Cookie;
  290.  
  291.             // The children field is set to either 0 or 1 (if it has children or not)
  292.             sdi.cChildren   = (Child[i].NumChildren==0)?0:1; 
  293.             
  294.             cns.InsertItem(ref sdi);
  295.             // Once the item has been inserted, we're given the HScopeItem value for the node
  296.             // MMC uses this value to uniquely identify the node. We'll store it for future
  297.             // use.
  298.             Child[i].HScopeItem = sdi.ID;
  299.             // We'll also put in the parent's HScopeItem
  300.             Child[i].m_iParentHScopeItem = HScopeItem;
  301.         }
  302.    
  303.     }// InsertChildren
  304.  
  305.     //-------------------------------------------------
  306.     // onShow
  307.     //
  308.     // This function will be used only if a column view is
  309.     // to be presented in the result pane.
  310.     //-------------------------------------------------
  311.     public void onShow(IConsole2 Console, int arg, int param)
  312.     {
  313.        // Let's make sure we do have a list view item to display
  314.        if (arg > 0 && m_oResults != null && m_oResults is IColumnResultView)
  315.        {
  316.         IColumnResultView crv = (IColumnResultView)m_oResults;
  317.             
  318.         // If we're here then we have stuff to add to the result
  319.         // view (beyond the standard view)
  320.  
  321.         // Query the Conole for a couple interfaces to use
  322.         IHeaderCtrl HeaderCtrl = (IHeaderCtrl)Console;
  323.         IResultData ResultData = (IResultData)Console;
  324.  
  325.         // Let's put in the column titles
  326.         int iNumCols = crv.getNumColumns(); 
  327.         for(int i=0; i < iNumCols; i++)
  328.             HeaderCtrl.InsertColumn(i, crv.getColumnTitles(i), LVCFMT.LEFT, MMCLV.AUTO);
  329.                 
  330.         // Note we're using RESULTDATAITEM (as opposed to RESULTDATAITEM2)
  331.         // because we need to assign the str field -1 to initiate a callback
  332.         RESULTDATAITEM rdi = new RESULTDATAITEM();
  333.  
  334.         for (int n = 0; n < crv.getNumRows(); n++)
  335.         {
  336.             rdi.mask  = RDI.STR    |   
  337.                         RDI.IMAGE  |
  338.                         RDI.PARAM;     
  339.  
  340.             rdi.nImage      = crv.GetImageIndex(n);                            
  341.             rdi.str         = -1;
  342.             rdi.nCol        = 0;
  343.  
  344.             // We're doing the lParam a little differently. The low word contains the cookie
  345.             // for this node, while the high word contains the row number + 1 we're inserting
  346.             rdi.lParam      = m_iCookie | ((n+1) << 16);
  347.                 
  348.             ResultData.InsertItem(ref rdi);
  349.                 
  350.         }
  351.        }
  352.     }// onShow
  353.  
  354.     //-------------------------------------------------
  355.     // GetDisplayInfo
  356.     //
  357.     // This function will provide MMC with information on how
  358.     // to display data items in the result pane. This function
  359.     // is used to get data both for a column view and a list view.
  360.     //-------------------------------------------------
  361.     public void GetDisplayInfo(ref RESULTDATAITEM ResultDataItem)
  362.     {
  363.         IColumnResultView crv = null;
  364.  
  365.         // See if we have info to display a column-view result
  366.         if (m_oResults is IColumnResultView)
  367.             crv = (IColumnResultView)m_oResults;
  368.  
  369.         // If we need a display name
  370.         if ((ResultDataItem.mask & RDI.STR) > 0)
  371.         {
  372.             // See if MMC is requesting an item for the column view
  373.             if (crv != null && (ResultDataItem.lParam >> 16) > 0)
  374.                 ResultDataItem.str = Marshal.StringToCoTaskMemUni(crv.getValues((ResultDataItem.lParam >> 16) -1 , ResultDataItem.nCol));
  375.             // Nope, it's just looking for the display name for the node
  376.             else
  377.                 ResultDataItem.str = Marshal.StringToCoTaskMemUni(m_sDisplayName);
  378.         }
  379.         // This snapin was set up so the node's image index is the 
  380.         // same as the node's cookie unless we're getting an image for a listview
  381.         if ((ResultDataItem.mask & RDI.IMAGE) > 0)
  382.         {
  383.             if (crv != null && (ResultDataItem.lParam >> 16) > 0)
  384.                 ResultDataItem.nImage = crv.GetImageIndex((ResultDataItem.lParam >> 16) -1);
  385.             else
  386.                 ResultDataItem.nImage = m_iCookie;
  387.         }
  388.  
  389.         if ((ResultDataItem.mask & RDI.PARAM) > 0)
  390.             ResultDataItem.lParam = m_iCookie;
  391.  
  392.         // Don't know what this field is for, MSDN isn't clear
  393.         // on it... just set it to 0 if we need to
  394.         if ((ResultDataItem.mask & (uint)RDI.INDEX) > 0)
  395.             ResultDataItem.nIndex = 0;
  396.                 
  397.         // Reserved
  398.         if ((ResultDataItem.mask & (uint)RDI.INDENT) > 0)
  399.             ResultDataItem.iIndent = 0;
  400.     }// GetDisplayInfo
  401.  
  402.     //-------------------------------------------------
  403.     // CreatePropertyPages
  404.     //
  405.     // This function will create property sheet pages based
  406.     // on the information stored in its m_aPropSheetPage field.
  407.     // It registers the property page along with the callback
  408.     // functions.
  409.     //-------------------------------------------------
  410.  
  411.     public void CreatePropertyPages(IPropertySheetCallback lpProvider, int handle)
  412.     {
  413.         int hPage;
  414.         PROPSHEETPAGE psp;
  415.  
  416.         // Grab onto the handle that MMC gives us
  417.         m_hPropertyPageRouter = handle;
  418.  
  419.         Object nThis = (Object)this;
  420.  
  421.         psp = new PROPSHEETPAGE();
  422.  
  423.         // Create delegates for our callbacks
  424.         m_MyDProc = new DialogProc(myDialogProc);
  425.         m_MyPProc = new PropSheetPageProc(myPropSheetPageProc); 
  426.  
  427.         for(int i=0; i<m_aPropSheetPage.Length; i++)
  428.         {
  429.             // Initialize each property sheet
  430.             m_aPropSheetPage[i].Init(ref nThis);
  431.  
  432.             psp.dwFlags = PSP.DEFAULT | PSP.USECALLBACK; 
  433.             psp.hInstance = m_hModule;
  434.             // We're using just a plain resource file as a "placeholder" for our WFC
  435.             // placed controls
  436.             psp.pszTemplate = "IDD_WFCWRAPPER";
  437.             psp.lParam = i;  
  438.             psp.pszTitle = (m_aPropSheetPage[i].Title()!=null)?m_aPropSheetPage[i].Title():"";
  439.             psp.hIcon = m_aPropSheetPage[i].Icon();
  440.  
  441.             // See if our property page uses a icon
  442.             if (psp.hIcon != -1)
  443.                 psp.dwFlags |= PSP.USEHICON;
  444.                     
  445.             // See if our property page uses a title
  446.             if (m_aPropSheetPage[i].Title()!=null)
  447.                 psp.dwFlags |= PSP.USETITLE;
  448.  
  449.             // Currently, we don't support the marshalling of delegates located in
  450.             // structures. Hence, a wrapper DLL exists that registers our property
  451.             // page with MMC. We need to make a call to that wrapper function and
  452.             // pass it our structure along with the two delegates we want to use
  453.  
  454.             hPage = RegisterPropertyPage(m_MyDProc, m_MyPProc, ref psp);
  455.             //hPage = CreatePropertySheetPage(psp);
  456.             // See if we were able to register the property page
  457.             if (hPage == 0)
  458.                 throw new Exception("Unable to RegisterPropertyPage");
  459.             else
  460.                 // Add the page to the property sheet
  461.                 lpProvider.AddPage(hPage);
  462.         }
  463.     }// CreatePropertyPages
  464.  
  465.     //-------------------------------------------------
  466.     // myPropSheetPageProc
  467.     //
  468.     // This callback is called whenever a property page
  469.     // is created or destroyed. Currently, we don't handle
  470.     // any messages... we just return appropriate values
  471.     //-------------------------------------------------
  472.     uint myPropSheetPageProc(int hwnd, uint uMsg, int lParam)
  473.     {
  474.         switch(uMsg)
  475.         {
  476.             case PSPCB.ADDREF:
  477.                 break;
  478.             case PSPCB.RELEASE:
  479.                 break;
  480.             case PSPCB.CREATE:
  481.                 // If everything is ok, we need to return a non-zero
  482.                 // number to create the page
  483.                 return 1;
  484.        }
  485.        
  486.        // We should return 0 for everything else 
  487.        return 0;
  488.      
  489.     }// myPropSheetPageProc
  490.  
  491.     //-------------------------------------------------
  492.     // myDialogProc
  493.     //
  494.     // This receives any messages that come back from 
  495.     // the property sheet we registered.
  496.     //-------------------------------------------------
  497.     int myDialogProc(int hwndDlg, uint uMsg, int wParam, int lParam)
  498.     {
  499.         int iIndex;
  500.         CNode nThis=this;
  501.     
  502.         switch (uMsg)
  503.         {
  504.             case WM.INITDIALOG:
  505.                 // lParam is really a pointer to a PROPSHEETPAGE....
  506.                 PROPSHEETPAGE pg = new PROPSHEETPAGE();
  507.                 pg = (PROPSHEETPAGE)Marshal.PtrToStructure(lParam, pg.GetType());
  508.                 // Tell the specified page to insert its controls
  509.                 m_aPropSheetPage[pg.lParam].InsertPropSheetPageControls(hwndDlg);
  510.  
  511.                 return 1;
  512.  
  513.             case WM.DESTROY:
  514.                 // tell MMC that we're done with the property sheet (we got this
  515.                 // handle in CreatePropertyPages
  516.                 callMMCFreeNotifyHandle(m_hPropertyPageRouter);
  517.                 break;
  518.  
  519.             case WM.NOTIFY:
  520.                 // lParam really is a pointer to a NMHDR structure....
  521.                 NMHDR nm = new NMHDR();
  522.                 nm = (NMHDR)Marshal.PtrToStructure(lParam, nm.GetType());
  523.                 
  524.                 // If we're being told to apply changes made in the property pages....
  525.                 if (nm.code == PSN.APPLY)
  526.                 {
  527.                     int iLength = m_aPropSheetPage.Length;
  528.                     for(iIndex = 0; iIndex < iLength; iIndex++)
  529.                         m_aPropSheetPage[iIndex].ApplyData();
  530.                 }
  531.                 break;
  532.  
  533.             default:
  534.                 // We'll let the default windows message handler handle the rest of
  535.                 // the messages
  536.                 return DefWindowProc(hwndDlg, uMsg, wParam, (int)lParam);
  537.         }
  538.         return  HRESULT.S_OK;
  539.     }// DialogProc
  540.  
  541.     //-------------------------------------------------
  542.     // StringToByteArray
  543.     //
  544.     // This function will convert a string to a byte array so
  545.     // it can be sent across the global stream in CDO 
  546.     //-------------------------------------------------
  547.     private byte[] StringToByteArray(String input)
  548.     {
  549.         int i;
  550.         int iStrLength = input.Length;
  551.         // Since MMC treats all its strings as unicode, 
  552.         // each character must be 2 bytes long
  553.         byte[] output = new byte[(iStrLength + 1)*2];
  554.         char[] cinput = input.ToCharArray();
  555.  
  556.         int j=0;
  557.         
  558.         for(i=0; i<iStrLength; i++)
  559.         {
  560.             output[j++] = (byte)cinput[i];
  561.             output[j++] = 0;
  562.         }
  563.  
  564.         // For the double null
  565.         output[j++]=0;
  566.         output[j]=0;
  567.         
  568.  
  569.         return output;
  570.  
  571.      }// StringToByteArray
  572.  
  573.     //-------------------------------------------------
  574.     // We need to import the Win32 API calls used to deal with
  575.     // image loading and messaging.
  576.     //-------------------------------------------------
  577.  
  578.     [DllImport("user32.dll")]
  579.     public static extern int LoadIcon(int hinst, String name);
  580.  
  581.     [DllImport("user32.dll")]
  582.     public static extern int DestroyIcon(int hIcon);
  583.  
  584.     [DllImport("user32.dll")]
  585.     public static extern int DefWindowProc(int a, uint b, int c, int d);
  586.  
  587.     //-------------------------------------------------
  588.     // Import the functions provided by our native helper-DLL
  589.     //-------------------------------------------------
  590.   
  591.     [DllImport("SampleMMCHelper.dll")]
  592.     public static extern int RegisterPropertyPage(DialogProc a, PropSheetPageProc b, ref PROPSHEETPAGE incoming);
  593.  
  594.     [DllImport("SampleMMCHelper.dll")]
  595.     public static extern int callMMCFreeNotifyHandle(int lNotifyHandle);
  596.  
  597.  
  598. }// class CNode
  599. }// namespace Microsoft.SampleMMC   
  600.     
  601.