home *** CD-ROM | disk | FTP | other *** search
- //-------------------------------------------------------------
- // CNode.cs
- //
- // This class represents individual nodes in the snapin.
- // It is responsible for virtually all aspects involving individual
- // nodes, ranging from adding children to displaying property pages.
- //-------------------------------------------------------------
-
- using System;
- using System.Runtime.InteropServices;
-
- namespace Microsoft.SampleMMC
- {
- public class CNode
- {
- private String m_sGuid; // The guid for this Node
- private String m_sHelpSection; // The link into the help file for this node
- private CNode[] m_naChildren; // The children this node has
- private String m_sDisplayName; // The display name
- private int m_iCookie; // The unique identifier for this node
- private int m_iHScopeItem; // MMC's unique identifier for this object
- public Object m_oResults; // The items that will be displayed in the result pane
- private int m_iResultNum; // If there are multiple results, the result to use
- private int m_hIcon; // The icon for this node
- private int m_iParentHScopeItem; // MMC's unique identifier for the parent
- private int m_hPropertyPageRouter; // MMC's handle for handling a Property sheet
- private IPropSheetPage[] m_aPropSheetPage; // The property pages for this item
- private DialogProc m_MyDProc; // The dialog callback
- private PropSheetPageProc m_MyPProc; // The property page callback
- private int m_hModule; // A handle to this module
-
- //-------------------------------------------------
- // CNode - Constructor
- //
- // This transfers data for the node information structure
- // into the class and loads the node's icon.
- //-------------------------------------------------
- public CNode(int initCookie, NodeInfo initNode)
- {
- m_iCookie = initCookie;
-
- // Pull all the info out of the structure
- m_sGuid = initNode.sGuid;
- m_sHelpSection = initNode.sHelpLink;
- m_sDisplayName = initNode.sName;
- m_oResults = initNode.oResults;
- m_aPropSheetPage = initNode.ppaPages;
- m_hModule = Marshal.GetHINSTANCE(this.GetType().Module);
-
- if (initNode.sIcon != null)
- m_hIcon = LoadIcon(m_hModule, initNode.sIcon);
- else
- m_hIcon = 0;
-
- m_iResultNum = 0;
- m_iHScopeItem = 0;
- }// CNode
-
- //-------------------------------------------------
- // ~CNode - Destructor
- //
- // The destructor destroys the icon associated with
- // this node
- //-------------------------------------------------
- ~CNode()
- {
- if (m_hIcon != 0)
- DestroyIcon(m_hIcon);
- }// ~CNode
-
- //-------------------------------------------------
- // The following methods allow access to the node's
- // private data members.
- //-------------------------------------------------
- public bool HavePropertyPages
- {
- get
- {
- return (m_aPropSheetPage != null);
- }
- }// HavePropertyPages
-
- public int ResultNum
- {
- get
- {
- return m_iResultNum;
- }
- set
- {
- m_iResultNum = value;
- }
- }// ResultNum
-
- public int ParentHScopeItem
- {
- get
- {
- return m_iParentHScopeItem;
- }
- }// ParentHScopeItem
-
- public int IconHandle
- {
- get
- {
- return m_hIcon;
- }
- }// IconHandle
-
- // This function will only return a result if the
- // result pane view is going to be an HTML page. All
- // other views are handled internally by the node.
- public String Result
- {
- get
- {
- if (m_oResults is String[])
- return ((String[])m_oResults)[m_iResultNum];
- else
- return null;
- }
- }// Result
-
- public int HScopeItem
- {
- get
- {
- return m_iHScopeItem;
- }
- set
- {
- m_iHScopeItem = value;
- }
- }// HScopeItem
-
- public int Cookie
- {
- get
- {
- return m_iCookie;
- }
- set
- {
- m_iCookie = value;
- }
- }// Cookie
-
-
- public String DisplayName
- {
- get
- {
- return m_sDisplayName;
- }
- set
- {
- m_sDisplayName = value;
- }
- }// DisplayName
-
- // This returns the displayname in a byte array, which
- // is required by IDataObject to send the name over a stream
- public byte[] bDisplayName
- {
- get
- {
- return StringToByteArray(m_sDisplayName);
- }
- }// bDisplayName
-
-
- public String Guid
- {
- get
- {
- return m_sGuid;
- }
- set
- {
- m_sGuid = value;
- }
- }// Guid
-
- // This returns the guid in a byte array, which
- // is required by IDataObject to send the guid over a stream
- public byte[] bGuid
- {
- get
- {
- return StringToByteArray(m_sGuid);
- }
- }// bGuid
-
-
- public String HelpSection
- {
- get
- {
- return m_sHelpSection;
- }
- set
- {
- m_sHelpSection = value;
- }
- }// HelpSection
-
- public int NumChildren
- {
- get
- {
- if (m_naChildren == null)
- return 0;
- else
- return m_naChildren.Length;
- }
- }// NumChildren
-
- public CNode[] Child
- {
- get
- {
- return m_naChildren;
- }
- }// Child
-
-
- //-------------------------------------------------
- // AddChild
- //
- // This function is called whenever we want to add
- // a child node to this node
- //-------------------------------------------------
- public void AddChild(ref CNode NewChild)
- {
- int i;
-
- CNode[] temp = new CNode[NumChildren + 1];
-
- for(i=0; i<NumChildren; i++)
- temp[i] = m_naChildren[i];
-
- // Now add the new element
- temp[i] = NewChild;
-
- // Now assign this new array to the internal array
- m_naChildren = temp;
- }// AddChild
-
- //-------------------------------------------------
- // InsertChildren
- //
- // This function sends all the node's children
- // information to MMC
- //-------------------------------------------------
- public void InsertChildren(ref IConsoleNameSpace2 cns, int thisHScopeItem)
- {
-
- // In the case of the first node, it won't have its HScopeItem field set yet.
- // We'll set that now
- m_iHScopeItem = thisHScopeItem;
-
- // Notice we're using SCOPEDATAITEM (instead of SCOPEDATAITEM2) because the
- // str field needs to have a number placed in it so we may initiate a callback
-
- SCOPEDATAITEM sdi = new SCOPEDATAITEM();
-
- int numChildren = NumChildren;
-
- for(int i=0; i<numChildren; i++)
- {
-
- sdi.mask = SDI.STR |
- SDI.PARAM |
- SDI.PARENT |
- SDI.IMAGE |
- SDI.OPENIMAGE |
- SDI.CHILDREN;
-
- // The image index is going to be the same as the cookie value
- sdi.nImage = Child[i].Cookie;
- // The open image is the same as the closed image
- sdi.nOpenImage = Child[i].Cookie;
- sdi.relativeID = thisHScopeItem;
- // We set displayname to -1 to initiate a callback for the string
- // (We need to do it this way... it's an MMCism)
- sdi.displayname = -1;
-
- sdi.lParam = Child[i].Cookie;
-
- // The children field is set to either 0 or 1 (if it has children or not)
- sdi.cChildren = (Child[i].NumChildren==0)?0:1;
-
- cns.InsertItem(ref sdi);
- // Once the item has been inserted, we're given the HScopeItem value for the node
- // MMC uses this value to uniquely identify the node. We'll store it for future
- // use.
- Child[i].HScopeItem = sdi.ID;
- // We'll also put in the parent's HScopeItem
- Child[i].m_iParentHScopeItem = HScopeItem;
- }
-
- }// InsertChildren
-
- //-------------------------------------------------
- // onShow
- //
- // This function will be used only if a column view is
- // to be presented in the result pane.
- //-------------------------------------------------
- public void onShow(IConsole2 Console, int arg, int param)
- {
- // Let's make sure we do have a list view item to display
- if (arg > 0 && m_oResults != null && m_oResults is IColumnResultView)
- {
- IColumnResultView crv = (IColumnResultView)m_oResults;
-
- // If we're here then we have stuff to add to the result
- // view (beyond the standard view)
-
- // Query the Conole for a couple interfaces to use
- IHeaderCtrl HeaderCtrl = (IHeaderCtrl)Console;
- IResultData ResultData = (IResultData)Console;
-
- // Let's put in the column titles
- int iNumCols = crv.getNumColumns();
- for(int i=0; i < iNumCols; i++)
- HeaderCtrl.InsertColumn(i, crv.getColumnTitles(i), LVCFMT.LEFT, MMCLV.AUTO);
-
- // Note we're using RESULTDATAITEM (as opposed to RESULTDATAITEM2)
- // because we need to assign the str field -1 to initiate a callback
- RESULTDATAITEM rdi = new RESULTDATAITEM();
-
- for (int n = 0; n < crv.getNumRows(); n++)
- {
- rdi.mask = RDI.STR |
- RDI.IMAGE |
- RDI.PARAM;
-
- rdi.nImage = crv.GetImageIndex(n);
- rdi.str = -1;
- rdi.nCol = 0;
-
- // We're doing the lParam a little differently. The low word contains the cookie
- // for this node, while the high word contains the row number + 1 we're inserting
- rdi.lParam = m_iCookie | ((n+1) << 16);
-
- ResultData.InsertItem(ref rdi);
-
- }
- }
- }// onShow
-
- //-------------------------------------------------
- // GetDisplayInfo
- //
- // This function will provide MMC with information on how
- // to display data items in the result pane. This function
- // is used to get data both for a column view and a list view.
- //-------------------------------------------------
- public void GetDisplayInfo(ref RESULTDATAITEM ResultDataItem)
- {
- IColumnResultView crv = null;
-
- // See if we have info to display a column-view result
- if (m_oResults is IColumnResultView)
- crv = (IColumnResultView)m_oResults;
-
- // If we need a display name
- if ((ResultDataItem.mask & RDI.STR) > 0)
- {
- // See if MMC is requesting an item for the column view
- if (crv != null && (ResultDataItem.lParam >> 16) > 0)
- ResultDataItem.str = Marshal.StringToCoTaskMemUni(crv.getValues((ResultDataItem.lParam >> 16) -1 , ResultDataItem.nCol));
- // Nope, it's just looking for the display name for the node
- else
- ResultDataItem.str = Marshal.StringToCoTaskMemUni(m_sDisplayName);
- }
- // This snapin was set up so the node's image index is the
- // same as the node's cookie unless we're getting an image for a listview
- if ((ResultDataItem.mask & RDI.IMAGE) > 0)
- {
- if (crv != null && (ResultDataItem.lParam >> 16) > 0)
- ResultDataItem.nImage = crv.GetImageIndex((ResultDataItem.lParam >> 16) -1);
- else
- ResultDataItem.nImage = m_iCookie;
- }
-
- if ((ResultDataItem.mask & RDI.PARAM) > 0)
- ResultDataItem.lParam = m_iCookie;
-
- // Don't know what this field is for, MSDN isn't clear
- // on it... just set it to 0 if we need to
- if ((ResultDataItem.mask & (uint)RDI.INDEX) > 0)
- ResultDataItem.nIndex = 0;
-
- // Reserved
- if ((ResultDataItem.mask & (uint)RDI.INDENT) > 0)
- ResultDataItem.iIndent = 0;
- }// GetDisplayInfo
-
- //-------------------------------------------------
- // CreatePropertyPages
- //
- // This function will create property sheet pages based
- // on the information stored in its m_aPropSheetPage field.
- // It registers the property page along with the callback
- // functions.
- //-------------------------------------------------
-
- public void CreatePropertyPages(IPropertySheetCallback lpProvider, int handle)
- {
- int hPage;
- PROPSHEETPAGE psp;
-
- // Grab onto the handle that MMC gives us
- m_hPropertyPageRouter = handle;
-
- Object nThis = (Object)this;
-
- psp = new PROPSHEETPAGE();
-
- // Create delegates for our callbacks
- m_MyDProc = new DialogProc(myDialogProc);
- m_MyPProc = new PropSheetPageProc(myPropSheetPageProc);
-
- for(int i=0; i<m_aPropSheetPage.Length; i++)
- {
- // Initialize each property sheet
- m_aPropSheetPage[i].Init(ref nThis);
-
- psp.dwFlags = PSP.DEFAULT | PSP.USECALLBACK;
- psp.hInstance = m_hModule;
- // We're using just a plain resource file as a "placeholder" for our WFC
- // placed controls
- psp.pszTemplate = "IDD_WFCWRAPPER";
- psp.lParam = i;
- psp.pszTitle = (m_aPropSheetPage[i].Title()!=null)?m_aPropSheetPage[i].Title():"";
- psp.hIcon = m_aPropSheetPage[i].Icon();
-
- // See if our property page uses a icon
- if (psp.hIcon != -1)
- psp.dwFlags |= PSP.USEHICON;
-
- // See if our property page uses a title
- if (m_aPropSheetPage[i].Title()!=null)
- psp.dwFlags |= PSP.USETITLE;
-
- // Currently, we don't support the marshalling of delegates located in
- // structures. Hence, a wrapper DLL exists that registers our property
- // page with MMC. We need to make a call to that wrapper function and
- // pass it our structure along with the two delegates we want to use
-
- hPage = RegisterPropertyPage(m_MyDProc, m_MyPProc, ref psp);
- //hPage = CreatePropertySheetPage(psp);
- // See if we were able to register the property page
- if (hPage == 0)
- throw new Exception("Unable to RegisterPropertyPage");
- else
- // Add the page to the property sheet
- lpProvider.AddPage(hPage);
- }
- }// CreatePropertyPages
-
- //-------------------------------------------------
- // myPropSheetPageProc
- //
- // This callback is called whenever a property page
- // is created or destroyed. Currently, we don't handle
- // any messages... we just return appropriate values
- //-------------------------------------------------
- uint myPropSheetPageProc(int hwnd, uint uMsg, int lParam)
- {
- switch(uMsg)
- {
- case PSPCB.ADDREF:
- break;
- case PSPCB.RELEASE:
- break;
- case PSPCB.CREATE:
- // If everything is ok, we need to return a non-zero
- // number to create the page
- return 1;
- }
-
- // We should return 0 for everything else
- return 0;
-
- }// myPropSheetPageProc
-
- //-------------------------------------------------
- // myDialogProc
- //
- // This receives any messages that come back from
- // the property sheet we registered.
- //-------------------------------------------------
- int myDialogProc(int hwndDlg, uint uMsg, int wParam, int lParam)
- {
- int iIndex;
- CNode nThis=this;
-
- switch (uMsg)
- {
- case WM.INITDIALOG:
- // lParam is really a pointer to a PROPSHEETPAGE....
- PROPSHEETPAGE pg = new PROPSHEETPAGE();
- pg = (PROPSHEETPAGE)Marshal.PtrToStructure(lParam, pg.GetType());
- // Tell the specified page to insert its controls
- m_aPropSheetPage[pg.lParam].InsertPropSheetPageControls(hwndDlg);
-
- return 1;
-
- case WM.DESTROY:
- // tell MMC that we're done with the property sheet (we got this
- // handle in CreatePropertyPages
- callMMCFreeNotifyHandle(m_hPropertyPageRouter);
- break;
-
- case WM.NOTIFY:
- // lParam really is a pointer to a NMHDR structure....
- NMHDR nm = new NMHDR();
- nm = (NMHDR)Marshal.PtrToStructure(lParam, nm.GetType());
-
- // If we're being told to apply changes made in the property pages....
- if (nm.code == PSN.APPLY)
- {
- int iLength = m_aPropSheetPage.Length;
- for(iIndex = 0; iIndex < iLength; iIndex++)
- m_aPropSheetPage[iIndex].ApplyData();
- }
- break;
-
- default:
- // We'll let the default windows message handler handle the rest of
- // the messages
- return DefWindowProc(hwndDlg, uMsg, wParam, (int)lParam);
- }
- return HRESULT.S_OK;
- }// DialogProc
-
- //-------------------------------------------------
- // StringToByteArray
- //
- // This function will convert a string to a byte array so
- // it can be sent across the global stream in CDO
- //-------------------------------------------------
- private byte[] StringToByteArray(String input)
- {
- int i;
- int iStrLength = input.Length;
- // Since MMC treats all its strings as unicode,
- // each character must be 2 bytes long
- byte[] output = new byte[(iStrLength + 1)*2];
- char[] cinput = input.ToCharArray();
-
- int j=0;
-
- for(i=0; i<iStrLength; i++)
- {
- output[j++] = (byte)cinput[i];
- output[j++] = 0;
- }
-
- // For the double null
- output[j++]=0;
- output[j]=0;
-
-
- return output;
-
- }// StringToByteArray
-
- //-------------------------------------------------
- // We need to import the Win32 API calls used to deal with
- // image loading and messaging.
- //-------------------------------------------------
-
- [DllImport("user32.dll")]
- public static extern int LoadIcon(int hinst, String name);
-
- [DllImport("user32.dll")]
- public static extern int DestroyIcon(int hIcon);
-
- [DllImport("user32.dll")]
- public static extern int DefWindowProc(int a, uint b, int c, int d);
-
- //-------------------------------------------------
- // Import the functions provided by our native helper-DLL
- //-------------------------------------------------
-
- [DllImport("SampleMMCHelper.dll")]
- public static extern int RegisterPropertyPage(DialogProc a, PropSheetPageProc b, ref PROPSHEETPAGE incoming);
-
- [DllImport("SampleMMCHelper.dll")]
- public static extern int callMMCFreeNotifyHandle(int lNotifyHandle);
-
-
- }// class CNode
- }// namespace Microsoft.SampleMMC
-
-