Exemple #1
0
 private void PickNode(System.Windows.Forms.TreeNode node)
 {
     if (this.IsServerNode(node))
     {
         if (this.ServerPicked != null)
         {
             this.ServerPicked((Opc.Da.Server)node.Tag);
         }
     }
     else if (this.IsBrowseElementNode(node))
     {
         BrowseElement browseElement = (BrowseElement)node.Tag;
         if (browseElement.IsItem && this.ItemPicked != null)
         {
             this.ItemPicked(new ItemIdentifier(browseElement.ItemPath, browseElement.ItemName));
         }
     }
     else if (this.IsItemPropertyNode(node))
     {
         ItemProperty itemProperty = (ItemProperty)node.Tag;
         if (itemProperty.ItemName != null && this.ItemPicked != null)
         {
             this.ItemPicked(new ItemIdentifier(itemProperty.ItemPath, itemProperty.ItemName));
         }
     }
 }
        private void recursiveTreeFill(Server server, string itemId)
        {
            BrowsePosition position;
            BrowseFilters  filters = new BrowseFilters()
            {
                BrowseFilter = browseFilter.all
            };

            ItemIdentifier item = (itemId == null) ? new ItemIdentifier() : new ItemIdentifier(itemId);

            BrowseElement[] browseElements = server.Browse(item, filters, out position);

            repository.Add(itemId, browseElements);

            for (int index = 0; index < browseElements.Length; index++)
            {
                BrowseElement browsedElement = browseElements[index];
                string        itemName       = browsedElement.ItemName;
                if (browsedElement.HasChildren)
                {
                    recursiveTreeFill(server, itemName);
                }
                else
                {
                    if (!repository.ContainsKey(itemId))
                    {
                        repository.Add(itemId, new BrowseElement[] { });
                    }
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Unmarshals and deallocates an array of OPCBROWSEELEMENT structures.
        /// </summary>
        internal static BrowseElement[] GetBrowseElements(ref IntPtr pInput, int count, bool deallocate)
        {
            BrowseElement[] output = null;

            if (pInput != IntPtr.Zero && count > 0)
            {
                output = new BrowseElement[count];

                IntPtr pos = pInput;

                for (int ii = 0; ii < count; ii++)
                {
                    output[ii] = GetBrowseElement(pos, deallocate);
                    pos        = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Da.OPCBROWSEELEMENT)));
                }

                if (deallocate)
                {
                    Marshal.FreeCoTaskMem(pInput);
                    pInput = IntPtr.Zero;
                }
            }

            return(output);
        }
Exemple #4
0
 private void AddBrowseElement(System.Windows.Forms.TreeNode parent, BrowseElement element)
 {
     System.Windows.Forms.TreeNode treeNode = new System.Windows.Forms.TreeNode(element.Name);
     if (element.IsItem)
     {
         treeNode.ImageIndex = (treeNode.SelectedImageIndex = Resources.IMAGE_GREEN_SCROLL);
     }
     else
     {
         treeNode.ImageIndex = (treeNode.SelectedImageIndex = Resources.IMAGE_CLOSED_YELLOW_FOLDER);
     }
     treeNode.Tag = element;
     if (element.HasChildren)
     {
         treeNode.Nodes.Add(new System.Windows.Forms.TreeNode());
     }
     if (element.Properties != null)
     {
         ItemProperty[] properties = element.Properties;
         for (int i = 0; i < properties.Length; i++)
         {
             ItemProperty property = properties[i];
             this.AddItemProperty(treeNode, property);
         }
     }
     parent.Nodes.Add(treeNode);
 }
 public void FillTagsTable(BrowseElement _element)
 {
     this.TagsDT.Clear();
     if (_element != null)
     {
         ItemIdentifier itemID         = new ItemIdentifier(_element.ItemPath, _element.ItemName);
         BrowsePosition browsePosition = new BrowsePosition(itemID, this.m_filters);
         if (_element.HasChildren)
         {
             BrowseElement[] array = this.server.Browse(itemID, this.m_filters, out browsePosition);
             if (array != null)
             {
                 BrowseElement[] array2 = array;
                 for (int i = 0; i < array2.Length; i++)
                 {
                     BrowseElement browseElement = array2[i];
                     if (!browseElement.ItemName.Contains("alrosa_w") && !browseElement.ItemName.Contains("List of"))
                     {
                         this.Browse(browseElement);
                     }
                 }
             }
         }
     }
 }
Exemple #6
0
        /// <summary>
        /// Unmarshals and deallocates a OPCBROWSEELEMENT structures.
        /// </summary>
        internal static BrowseElement GetBrowseElement(IntPtr pInput, bool deallocate)
        {
            BrowseElement output = null;

            if (pInput != IntPtr.Zero)
            {
                OpcRcw.Da.OPCBROWSEELEMENT element = (OpcRcw.Da.OPCBROWSEELEMENT)Marshal.PtrToStructure(pInput, typeof(OpcRcw.Da.OPCBROWSEELEMENT));

                output = new BrowseElement();

                output.Name        = element.szName;
                output.ItemPath    = null;
                output.ItemName    = element.szItemID;
                output.IsItem      = ((element.dwFlagValue & OpcRcw.Da.Constants.OPC_BROWSE_ISITEM) != 0);
                output.HasChildren = ((element.dwFlagValue & OpcRcw.Da.Constants.OPC_BROWSE_HASCHILDREN) != 0);
                output.Properties  = GetItemProperties(ref element.ItemProperties, deallocate);

                if (deallocate)
                {
                    Marshal.DestroyStructure(pInput, typeof(OpcRcw.Da.OPCBROWSEELEMENT));
                }
            }

            return(output);
        }
Exemple #7
0
            /// <summary>
            /// Gets the browse element.
            /// </summary>
            /// <returns>BrowseElement.</returns>
            public BrowseElement GetBrowseElement()
            {
                BrowseElement el =
                    new BrowseElement()
                {
                    HasChildren = this.HasChildren, IsItem = IsItem, ItemName = ItemName, Name = Name
                };

                if (!IsItemPathNull())
                {
                    el.ItemPath = ItemPath;
                }
                if (GetItemPropertiesTableRows().Length == 0)
                {
                    return(el);
                }
                ArrayList prprts = new ArrayList();

                prprts.AddRange(GetItemPropertiesTableRows());
                el.Properties = new ItemProperty[prprts.Count];
                for (int ix = 0; ix < el.Properties.Length; ix++)
                {
                    el.Properties[ix] = ((ItemPropertiesTableRow)prprts[ix]).GetItemPropery();
                }
                return(el);
            }
Exemple #8
0
 private int FetchElements(BrowseType browseType, int maxElements, UCOMIEnumString enumerator, ArrayList elements)
 {
     string[] rgelt = new string[1];
     int celt = ((maxElements > 0) && ((maxElements - elements.Count) < rgelt.Length)) ? (maxElements - elements.Count) : rgelt.Length;
     int pceltFetched = 0;
     int num3 = enumerator.Next(celt, rgelt, out pceltFetched);
     while (num3 == 0)
     {
         for (int i = 0; i < pceltFetched; i++)
         {
             BrowseElement element = new BrowseElement {
                 Name = rgelt[i],
                 QualifiedName = this.GetQualifiedName(rgelt[i], browseType),
                 NodeType = browseType
             };
             elements.Add(element);
         }
         if ((maxElements > 0) && (elements.Count >= maxElements))
         {
             return num3;
         }
         celt = ((maxElements > 0) && ((maxElements - elements.Count) < rgelt.Length)) ? (maxElements - elements.Count) : rgelt.Length;
         num3 = enumerator.Next(celt, rgelt, out pceltFetched);
     }
     return num3;
 }
Exemple #9
0
 // Token: 0x0600035C RID: 860 RVA: 0x00009164 File Offset: 0x00008164
 private bool Init(BrowseElement element)
 {
     base.ItemPath = element.ItemPath;
     base.ItemName = element.ItemName;
     this.m_name   = element.Name;
     return(this.Init(element.Properties));
 }
Exemple #10
0
        /// <summary>
        /// Initializes the object from a browse element.
        /// </summary>
        private bool Init(BrowseElement element)
        {
            // update the item id.
            ItemPath = element.ItemPath;
            ItemName = element.ItemName;
            m_name   = element.Name;

            return(Init(element.Properties));
        }
Exemple #11
0
        private BrowseElement GetElement(string name, BrowseFilters filters, bool isBranch)
        {
            if (name == null)
            {
                return(null);
            }
            BrowseElement element = new BrowseElement {
                Name        = name,
                HasChildren = isBranch,
                ItemPath    = null
            };

            try
            {
                string szItemID = null;
                ((IOPCBrowseServerAddressSpace)base.m_server).GetItemID(element.Name, out szItemID);
                element.ItemName = szItemID;
                OPCITEMDEF opcitemdef = new OPCITEMDEF {
                    szItemID            = element.ItemName,
                    szAccessPath        = null,
                    hClient             = 0,
                    bActive             = 0,
                    vtRequestedDataType = 0,
                    dwBlobSize          = 0,
                    pBlob = IntPtr.Zero
                };
                IntPtr       zero       = IntPtr.Zero;
                IntPtr       ppErrors   = IntPtr.Zero;
                OPCITEMDEF[] pItemArray = new OPCITEMDEF[] { opcitemdef };
                ((IOPCItemMgt)this.m_group).ValidateItems(1, pItemArray, 0, out zero, out ppErrors);
                OpcCom.Da.Interop.GetItemResults(ref zero, 1, true);
                int[] numArray = OpcCom.Interop.GetInt32s(ref ppErrors, 1, true);
                element.IsItem = numArray[0] >= 0;
            }
            catch
            {
                element.ItemName = null;
            }
            try
            {
                if (filters.ReturnAllProperties)
                {
                    element.Properties = this.GetProperties(element.ItemName, null, filters.ReturnPropertyValues);
                    return(element);
                }
                if (filters.PropertyIDs != null)
                {
                    element.Properties = this.GetProperties(element.ItemName, filters.PropertyIDs, filters.ReturnPropertyValues);
                }
            }
            catch
            {
                element.Properties = null;
            }
            return(element);
        }
Exemple #12
0
 public void Browse(System.Windows.Forms.TreeNode node)
 {
     try
     {
         Opc.Da.Server  server = this.FindServer(node);
         ItemIdentifier itemID = null;
         if (node.Tag != null && node.Tag.GetType() == typeof(BrowseElement))
         {
             BrowseElement browseElement = (BrowseElement)node.Tag;
             itemID = new ItemIdentifier(browseElement.ItemPath, browseElement.ItemName);
         }
         node.Nodes.Clear();
         BrowsePosition  browsePosition = null;
         BrowseElement[] array          = server.Browse(itemID, this.m_filters, out browsePosition);
         if (array != null)
         {
             BrowseElement[] array2 = array;
             for (int i = 0; i < array2.Length; i++)
             {
                 BrowseElement browseElement2 = array2[i];
                 if (!browseElement2.ItemName.Contains("alrosa_w") && !browseElement2.ItemName.Contains("List of"))
                 {
                     if (!browseElement2.IsItem)
                     {
                         this.AddBrowseElement(node, browseElement2);
                     }
                 }
             }
             node.Expand();
         }
         while (browsePosition != null)
         {
             System.Windows.Forms.DialogResult dialogResult = System.Windows.Forms.MessageBox.Show("More items meeting search criteria exist. Continue browse?", "Browse Items", System.Windows.Forms.MessageBoxButtons.YesNo);
             if (dialogResult == System.Windows.Forms.DialogResult.No)
             {
                 break;
             }
             array = server.BrowseNext(ref browsePosition);
             if (array != null)
             {
                 BrowseElement[] array2 = array;
                 for (int i = 0; i < array2.Length; i++)
                 {
                     BrowseElement browseElement2 = array2[i];
                     this.AddBrowseElement(node, browseElement2);
                 }
                 node.Expand();
             }
         }
     }
     catch (System.Exception ex)
     {
         System.Windows.Forms.MessageBox.Show(ex.Message);
     }
 }
 public static ComplexItem GetComplexItem(BrowseElement element)
 {
     if (element == null)
     {
         return(null);
     }
     lock (typeof(ComplexTypeCache))
     {
         return(GetComplexItem(new ItemIdentifier(element.ItemPath, element.ItemName)));
     }
 }
Exemple #14
0
 private void TagGridCTRL_ElementSelected(BrowseElement element)
 {
     this.PropertiesCTRL.Initialize(element);
     if (element != null)
     {
         this.DoneBTN.Enabled = element.IsItem;
     }
     else
     {
         this.DoneBTN.Enabled = false;
     }
 }
Exemple #15
0
 private void OnElementSelected(BrowseElement element)
 {
     this.TagGridCTRL.FillTagsTable(element);
     if (element != null)
     {
         this.DoneBTN.Enabled = element.IsItem;
     }
     else
     {
         this.DoneBTN.Enabled = false;
     }
     this._element = element;
 }
Exemple #16
0
 private void OnBrowseFiltersChanged(BrowseFilters filters)
 {
     this.m_filters = filters;
     if (this.IsBrowseElementNode(this.BrowseTV.SelectedNode))
     {
         BrowseElement browseElement = (BrowseElement)this.BrowseTV.SelectedNode.Tag;
         if (!browseElement.HasChildren)
         {
             this.GetProperties(this.BrowseTV.SelectedNode);
             return;
         }
     }
     this.Browse(this.BrowseTV.SelectedNode);
 }
Exemple #17
0
 public void Initialize(BrowseElement element)
 {
     this.PropertiesLV.Items.Clear();
     if (element != null && element.Properties != null)
     {
         this.m_element = element;
         ItemProperty[] properties = element.Properties;
         for (int i = 0; i < properties.Length; i++)
         {
             ItemProperty property = properties[i];
             this.AddProperty(property);
         }
         this.AdjustColumns();
     }
 }
Exemple #18
0
        private ArrayList FetchElements(EnumString enumerator, int maxElements, bool isBranch)
        {
            ArrayList list = new ArrayList();

            while (list.Count < maxElements)
            {
                int count = 10;
                if ((list.Count + count) > maxElements)
                {
                    count = maxElements - list.Count;
                }
                string[] strArray = enumerator.Next(count);
                if ((strArray == null) || (strArray.Length == 0))
                {
                    break;
                }
                foreach (string str in strArray)
                {
                    BrowseElement element = new BrowseElement {
                        Name = str
                    };
                    try
                    {
                        string pszItemID = null;
                        this.m_browser.GetItemID(str, out pszItemID);
                        element.ItemName    = pszItemID;
                        element.ItemPath    = null;
                        element.HasChildren = isBranch;
                    }
                    catch
                    {
                    }
                    list.Add(element);
                }
            }
            IdentifiedResult[] resultArray = this.m_server.ValidateItems((ItemIdentifier[])list.ToArray(typeof(ItemIdentifier)));
            if (resultArray != null)
            {
                for (int i = 0; i < resultArray.Length; i++)
                {
                    if (resultArray[i].ResultID.Succeeded())
                    {
                        ((BrowseElement)list[i]).IsItem = true;
                    }
                }
            }
            return(list);
        }
Exemple #19
0
 private void GetProperties(System.Windows.Forms.TreeNode node)
 {
     try
     {
         Opc.Da.Server server        = this.FindServer(node);
         BrowseElement browseElement = null;
         if (node.Tag != null && node.Tag.GetType() == typeof(BrowseElement))
         {
             browseElement = (BrowseElement)node.Tag;
         }
         if (browseElement.IsItem)
         {
             node.Nodes.Clear();
             ItemIdentifier           itemIdentifier = new ItemIdentifier(browseElement.ItemPath, browseElement.ItemName);
             ItemPropertyCollection[] properties     = server.GetProperties(new ItemIdentifier[]
             {
                 itemIdentifier
             }, this.m_filters.PropertyIDs, this.m_filters.ReturnPropertyValues);
             if (properties != null)
             {
                 ItemPropertyCollection[] array = properties;
                 for (int i = 0; i < array.Length; i++)
                 {
                     ItemPropertyCollection itemPropertyCollection = array[i];
                     foreach (ItemProperty property in itemPropertyCollection)
                     {
                         this.AddItemProperty(node, property);
                     }
                     browseElement.Properties = (ItemProperty[])itemPropertyCollection.ToArray(typeof(ItemProperty));
                 }
             }
             node.Expand();
             if (this.ElementSelected != null)
             {
                 this.ElementSelected(browseElement);
             }
         }
     }
     catch (System.Exception ex)
     {
         System.Windows.Forms.MessageBox.Show(ex.Message);
     }
 }
Exemple #20
0
            /// <summary>
            /// Adds the row.
            /// </summary>
            /// <param name="item">The item.</param>
            /// <param name="parentID">The parent identifier.</param>
            /// <param name="serverRelated">if set to <c>true</c> [server related].</param>
            /// <returns>TagsTableRow.</returns>
            public TagsTableRow AddRow(BrowseElement item, int parentID, bool serverRelated)
            {
                TagsTableRow mRow = this.NewTagsTableRow();

                mRow.HasChildren = item.HasChildren;
                mRow.IsItem      = item.IsItem;
                mRow.ItemName    = item.ItemName;
                mRow.ItemPath    = item.ItemPath;
                mRow.Name        = item.Name;
                if (serverRelated)
                {
                    mRow.ServerID = parentID;
                }
                else
                {
                    mRow.TagID = parentID;
                }
                this.AddTagsTableRow(mRow);
                return(mRow);
            }
Exemple #21
0
 internal static BrowseElement[] GetBrowseElements(ref IntPtr pInput, int count, bool deallocate)
 {
     BrowseElement[] elementArray = null;
     if ((pInput != IntPtr.Zero) && (count > 0))
     {
         elementArray = new BrowseElement[count];
         IntPtr ptr = pInput;
         for (int i = 0; i < count; i++)
         {
             elementArray[i] = GetBrowseElement(ptr, deallocate);
             ptr             = (IntPtr)(ptr.ToInt32() + Marshal.SizeOf(typeof(OPCBROWSEELEMENT)));
         }
         if (deallocate)
         {
             Marshal.FreeCoTaskMem(pInput);
             pInput = IntPtr.Zero;
         }
     }
     return(elementArray);
 }
Exemple #22
0
        internal static OPCBROWSEELEMENT GetBrowseElement(BrowseElement input, bool propertiesRequested)
        {
            OPCBROWSEELEMENT opcbrowseelement = new OPCBROWSEELEMENT();

            if (input != null)
            {
                opcbrowseelement.szName         = input.Name;
                opcbrowseelement.szItemID       = input.ItemName;
                opcbrowseelement.dwFlagValue    = 0;
                opcbrowseelement.ItemProperties = GetItemProperties(input.Properties);
                if (input.IsItem)
                {
                    opcbrowseelement.dwFlagValue |= 2;
                }
                if (input.HasChildren)
                {
                    opcbrowseelement.dwFlagValue |= 1;
                }
            }
            return(opcbrowseelement);
        }
Exemple #23
0
 public void GetItemID(string szItemDataID, out string szItemID)
 {
     OpcCom.Da.Wrapper.Server server;
     Monitor.Enter(server = this);
     try
     {
         if ((szItemDataID == null) || (szItemDataID.Length == 0))
         {
             if (this.m_browseStack.Count == 0)
             {
                 szItemID = "";
             }
             else
             {
                 szItemID = ((ItemIdentifier)this.m_browseStack.Peek()).ItemName;
             }
         }
         else if (this.IsItem(szItemDataID))
         {
             szItemID = szItemDataID;
         }
         else
         {
             BrowseElement element = this.FindChild(szItemDataID);
             if (element == null)
             {
                 throw CreateException(-2147024809);
             }
             szItemID = element.ItemName;
         }
     }
     catch (Exception exception)
     {
         throw CreateException(exception);
     }
     finally
     {
         Monitor.Exit(server);
     }
 }
Exemple #24
0
        public void GetItemID(string szItemDataID, out string szItemID)
        {
            lock (this)
            {
                try
                {
                    if (szItemDataID == null || szItemDataID.Length == 0)
                    {
                        if (m_browseStack.Count == 0)
                        {
                            szItemID = "";
                        }
                        else
                        {
                            szItemID = ((ItemIdentifier)m_browseStack.Peek()).ItemName;
                        }

                        return;
                    }

                    if (IsItem(szItemDataID))
                    {
                        szItemID = szItemDataID;
                        return;
                    }

                    BrowseElement browseElement = FindChild(szItemDataID);
                    if (browseElement == null)
                    {
                        throw CreateException(-2147024809);
                    }

                    szItemID = browseElement.ItemName;
                }
                catch (Exception e)
                {
                    throw CreateException(e);
                }
            }
        }
Exemple #25
0
        internal static BrowseElement GetBrowseElement(IntPtr pInput, bool deallocate)
        {
            BrowseElement browseElement = null;

            if (pInput != IntPtr.Zero)
            {
                OPCBROWSEELEMENT oPCBROWSEELEMENT = (OPCBROWSEELEMENT)Marshal.PtrToStructure(pInput, typeof(OPCBROWSEELEMENT));
                browseElement             = new BrowseElement();
                browseElement.Name        = oPCBROWSEELEMENT.szName;
                browseElement.ItemPath    = null;
                browseElement.ItemName    = oPCBROWSEELEMENT.szItemID;
                browseElement.IsItem      = ((oPCBROWSEELEMENT.dwFlagValue & 2) != 0);
                browseElement.HasChildren = ((oPCBROWSEELEMENT.dwFlagValue & 1) != 0);
                browseElement.Properties  = GetItemProperties(ref oPCBROWSEELEMENT.ItemProperties, deallocate);
                if (deallocate)
                {
                    Marshal.DestroyStructure(pInput, typeof(OPCBROWSEELEMENT));
                }
            }

            return(browseElement);
        }
 private void TagsDGV_CellDoubleClick(object sender, System.Windows.Forms.DataGridViewCellEventArgs e)
 {
     if (this.TagsDGV.CurrentRow != null)
     {
         System.Data.DataRow row = (this.TagsDGV.CurrentRow.DataBoundItem as System.Data.DataRowView).Row;
         if (!row.IsNull("Element"))
         {
             BrowseElement browseElement = (BrowseElement)row["Element"];
             if (browseElement.IsItem)
             {
                 if (browseElement.IsItem && this.ElementPicked != null)
                 {
                     this.ElementPicked(browseElement);
                 }
             }
             else
             {
                 this.FillTagsTable(browseElement);
             }
         }
     }
 }
Exemple #27
0
        internal static BrowseElement GetBrowseElement(IntPtr pInput, bool deallocate)
        {
            BrowseElement element = null;

            if (pInput != IntPtr.Zero)
            {
                OPCBROWSEELEMENT opcbrowseelement = (OPCBROWSEELEMENT)Marshal.PtrToStructure(pInput, typeof(OPCBROWSEELEMENT));
                element = new BrowseElement {
                    Name        = opcbrowseelement.szName,
                    ItemPath    = null,
                    ItemName    = opcbrowseelement.szItemID,
                    IsItem      = (opcbrowseelement.dwFlagValue & 2) != 0,
                    HasChildren = (opcbrowseelement.dwFlagValue & 1) != 0,
                    Properties  = GetItemProperties(ref opcbrowseelement.ItemProperties, deallocate)
                };
                if (deallocate)
                {
                    Marshal.DestroyStructure(pInput, typeof(OPCBROWSEELEMENT));
                }
            }
            return(element);
        }
Exemple #28
0
        internal static BrowseElement[] GetBrowseElements(ref IntPtr pInput, int count, bool deallocate)
        {
            BrowseElement[] array = null;
            if (pInput != IntPtr.Zero && count > 0)
            {
                array = new BrowseElement[count];
                IntPtr pInput2 = pInput;
                for (int i = 0; i < count; i++)
                {
                    array[i] = GetBrowseElement(pInput2, deallocate);
                    pInput2  = (IntPtr)(pInput2.ToInt64() + Marshal.SizeOf(typeof(OPCBROWSEELEMENT)));
                }

                if (deallocate)
                {
                    Marshal.FreeCoTaskMem(pInput);
                    pInput = IntPtr.Zero;
                }
            }

            return(array);
        }
Exemple #29
0
        internal static OPCBROWSEELEMENT GetBrowseElement(BrowseElement input, bool propertiesRequested)
        {
            OPCBROWSEELEMENT result = default(OPCBROWSEELEMENT);

            if (input != null)
            {
                result.szName         = input.Name;
                result.szItemID       = input.ItemName;
                result.dwFlagValue    = 0;
                result.ItemProperties = GetItemProperties(input.Properties);
                if (input.IsItem)
                {
                    result.dwFlagValue |= 2;
                }

                if (input.HasChildren)
                {
                    result.dwFlagValue |= 1;
                }
            }

            return(result);
        }
Exemple #30
0
        /// <summary>
        /// Allocates and marshals an OPCBROWSEELEMENT structure.
        /// </summary>
        internal static OpcRcw.Da.OPCBROWSEELEMENT GetBrowseElement(BrowseElement input, bool propertiesRequested)
        {
            OpcRcw.Da.OPCBROWSEELEMENT output = new OpcRcw.Da.OPCBROWSEELEMENT();

            if (input != null)
            {
                output.szName         = input.Name;
                output.szItemID       = input.ItemName;
                output.dwFlagValue    = 0;
                output.ItemProperties = GetItemProperties(input.Properties);

                if (input.IsItem)
                {
                    output.dwFlagValue |= OpcRcw.Da.Constants.OPC_BROWSE_ISITEM;
                }

                if (input.HasChildren)
                {
                    output.dwFlagValue |= OpcRcw.Da.Constants.OPC_BROWSE_HASCHILDREN;
                }
            }

            return(output);
        }
        /// <summary>
        /// Recursively browses the address space.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="parent">The parent.</param>
        /// <param name="nameFilter">The name filter.</param>
        /// <param name="dataTypeFilter">The data type filter.</param>
        /// <param name="accessRightsFilter">The access rights filter.</param>
        /// <param name="branches">The table of followed branches.</param>
        /// <param name="hits">The item ids found for variables that meet the criteria.</param>
        private void BrowseFlat(
            Session session,
            BrowseElement parent,
            string nameFilter,
            short dataTypeFilter,
            int accessRightsFilter,
            Dictionary<string, BrowseElement> branches,
            List<string> hits)
        {
            // fetch the children.
            List<BrowseElement> children = LookupChildElements(session, parent);

            for (int ii = 0; ii < children.Count; ii++)
            {
                BrowseElement child = children[ii];

                // recusively follow branches but need to guard against loops.
                if (child.ReferencesByName.Count > 0)
                {
                    if (!branches.ContainsKey(child.ItemId))
                    {
                        branches.Add(child.ItemId, child);
                        BrowseFlat(session, child, nameFilter, dataTypeFilter, accessRightsFilter, branches, hits);
                    }
                }

                // nothing more to do if not a variable.
                if (child.NodeClass != NodeClass.Variable)
                {
                    continue;
                }

                // apply the name filter to the item id.
                if (!String.IsNullOrEmpty(nameFilter))
                {
                    if (!ComUtils.Match(child.ItemId, nameFilter, false))
                    {
                        continue;
                    }
                }

                // apply data type filter.
                if (dataTypeFilter != 0)
                {
                    if (child.CanonicalDataType != dataTypeFilter)
                    {
                        continue;
                    }
                }

                // apply access rights filter.
                if (accessRightsFilter != 0)
                {
                    if ((child.AccessRights & accessRightsFilter) == 0)
                    {
                        continue;
                    }
                }

                // a match.
                hits.Add(child.ItemId);
            }
        }
        /// <summary>
        /// Creates the browse element.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="nodeId">The node id.</param>
        /// <returns>The browse element; null if the node id does not refers to a valid element.</returns>
        private BrowseElement CreateBrowseElement(Session session, NodeId nodeId)
        {
            TraceState("CreateBrowseElement", nodeId);
            BrowseElement element = new BrowseElement();

            element.NodeId = nodeId;
            element.ItemId = m_mapper.GetLocalItemId(nodeId);

            // browse the server for the children.
            BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
            int index = PrepareBrowseElementBrowseRequest(nodeId, nodesToBrowse);

            // browse all elements at once.
            BrowseResultCollection results = Browse(session, nodesToBrowse);

            // update the element with the children found.
            if (!UpdateBrowseElement(element, nodesToBrowse, results, index))
            {
                return null;
            }

            // read the properties from the server.
            ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
            index = PrepareBrowseElementReadRequest(nodeId, element.ReferencesByName, nodesToRead, NodeClass.Unspecified, true);

            DataValueCollection values = Read(session, nodesToRead);

            // update the browse element with the property values.
            if (!UpdateBrowseElement(session.TypeTree, element, nodesToRead, values, NodeClass.Unspecified, true, index))
            {
                return null;
            }

            return element;
        }
 /// <summary>
 /// Sets the element masks.
 /// </summary>
 /// <param name="element">The element to update.</param>
 private void SetElementMasks(BrowseElement element)
 {
     element.HasChildren = (element.ReferencesByName.Count > 0);
     element.IsItem = (element.NodeClass == NodeClass.Variable);
 }
        /// <summary>
        /// Updates the browse element with the properties return in the read results.
        /// </summary>
        /// <param name="typeTree">The type tree.</param>
        /// <param name="element">The element.</param>
        /// <param name="nodesToRead">The nodes to read.</param>
        /// <param name="values">The values.</param>        
        /// <param name="nodeClass">The node class - passed only if all of the information in the ReferenceDescription is available.</param>
        /// <param name="onlyEssentialProperties">If true the only properties essential for browing were fetched.</param>
        /// <param name="first">The first.</param>
        /// <returns></returns>
        private bool UpdateBrowseElement(
            ITypeTable typeTree,
            BrowseElement element,
            ReadValueIdCollection nodesToRead,
            DataValueCollection values,
            NodeClass nodeClass,
            bool onlyEssentialProperties,
            int first)
        {
            // check for a valid range within the collection.
            if (first < 0 || first >= nodesToRead.Count)
            {
                return false;
            }

            if (nodeClass == NodeClass.Unspecified)
            {
                // verify node class.
                NodeClass actualNodeClass = (NodeClass)values[first++].GetValue<int>((int)NodeClass.Unspecified);

                if (actualNodeClass != NodeClass.Variable && actualNodeClass != NodeClass.Object)
                {
                    return false;
                }

                element.NodeClass = actualNodeClass;

                // verify browse name.
                QualifiedName browseName = values[first++].GetValue<QualifiedName>(null);

                if (QualifiedName.IsNull(browseName))
                {
                    return false;
                }

                element.BrowseName = element.UaBrowseName = m_mapper.GetLocalBrowseName(browseName);

                // verify display name.
                LocalizedText displayName = values[first++].GetValue<LocalizedText>(null);

                if (LocalizedText.IsNullOrEmpty(displayName))
                {
                    return false;
                }

                element.BrowseName = displayName.Text;
            }

            if (!onlyEssentialProperties)
            {
                // check if long description exists.
                LocalizedText description = values[first++].GetValue<LocalizedText>(null);

                if (!LocalizedText.IsNullOrEmpty(description))
                {
                    element.UaDescription = description.Text;
                }
                else
                {
                    element.UaDescription = "";
                }
            }

            // update the masks.
            SetElementMasks(element);

            // nothing more to do.
            if (nodeClass == NodeClass.Object)
            {
                return true;
            }

            // verify data type.
            NodeId dataTypeId = values[first++].GetValue<NodeId>(null);

            if (dataTypeId == null && element.NodeClass == NodeClass.Variable)
            {
                return false;
            }

            int valueRank = values[first++].GetValue<int>(ValueRanks.Scalar);

            // update data type information.
            if (dataTypeId != null)
            {
                element.BuiltInType = DataTypes.GetBuiltInType(dataTypeId, typeTree);
                element.DataTypeId = m_mapper.GetLocalItemId(dataTypeId);
                element.ValueRank = valueRank;
                element.CanonicalDataType = (short)ComUtils.GetVarType(new TypeInfo(element.BuiltInType, element.ValueRank));
            }

            if (!onlyEssentialProperties)
            {
                // update scan rate.
                element.ScanRate = (float)values[first++].GetValue<double>(MinimumSamplingIntervals.Indeterminate);

                // update access rights.
                byte userAccessLevel = values[first++].GetValue<byte>(0);

                if ((userAccessLevel & AccessLevels.CurrentRead) != 0)
                {
                    element.AccessRights |= OpcRcw.Da.Constants.OPC_READABLE;
                }

                if ((userAccessLevel & AccessLevels.CurrentWrite) != 0)
                {
                    element.AccessRights |= OpcRcw.Da.Constants.OPC_WRITEABLE;
                }

                if ((userAccessLevel & AccessLevels.HistoryRead) != 0)
                {
                    element.IsHistoricalItem = true;
                }

                // cache the latest value.
                DataValue value = values[first++];

                if (element.NodeClass == NodeClass.Variable)
                {
                    element.LastValue = m_mapper.GetLocalDataValue(value);
                }

                // update HighEU and LowEU
                element.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM;
                element.HighEU = Double.MaxValue;
                element.LowEU = Double.MaxValue;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.EURange))
                {
                    Range euRange = values[first++].GetValue<Range>(null);

                    if (euRange != null)
                    {
                        element.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG;
                        element.HighEU = euRange.High;
                        element.LowEU = euRange.Low;
                    }
                }

                // update HighIR and LowIR
                element.HighIR = Double.MaxValue;
                element.LowIR = Double.MaxValue;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.InstrumentRange))
                {
                    Range instrumentRange = values[first++].GetValue<Range>(null);

                    if (instrumentRange != null)
                    {
                        element.HighIR = instrumentRange.High;
                        element.LowIR = instrumentRange.Low;
                    }
                }

                // update EngineeringUnits
                element.EngineeringUnits = null;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.EngineeringUnits))
                {
                    EUInformation engineeringUnits = values[first++].GetValue<EUInformation>(null);

                    if (engineeringUnits != null && engineeringUnits.DisplayName != null)
                    {
                        element.EngineeringUnits = engineeringUnits.DisplayName.Text;
                    }
                }

                // update EUInfo
                element.EuInfo = null;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.EnumStrings))
                {
                    LocalizedText[] enumStrings = values[first++].GetValue<LocalizedText[]>(null);

                    if (enumStrings != null)
                    {
                        string[] strings = new string[enumStrings.Length];

                        for (int ii = 0; ii < enumStrings.Length; ii++)
                        {
                            if (enumStrings[ii] != null)
                            {
                                strings[ii] = enumStrings[ii].Text;
                            }
                        }

                        element.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED;
                        element.EuInfo = strings;
                    }
                }

                // update CloseLabel
                element.CloseLabel = null;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.TrueState))
                {
                    LocalizedText trueState = values[first++].GetValue<LocalizedText>(null);

                    if (trueState != null)
                    {
                        element.CloseLabel = trueState.Text;
                    }
                }

                // update OpenLabel
                element.OpenLabel = null;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.FalseState))
                {
                    LocalizedText falseState = values[first++].GetValue<LocalizedText>(null);

                    if (falseState != null)
                    {
                        element.OpenLabel = falseState.Text;
                    }
                }

                // update TimeZone
                element.TimeZone = Int32.MaxValue;

                if (element.ReferencesByName.ContainsKey(Opc.Ua.BrowseNames.LocalTime))
                {
                    TimeZoneDataType timeZone = values[first++].GetValue<TimeZoneDataType>(null);

                    if (timeZone != null)
                    {
                        element.TimeZone = timeZone.Offset;
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Updates the browse element with the children returned in the browse results.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="nodesToBrowse">The nodes to browse.</param>
        /// <param name="results">The results.</param>
        /// <param name="first">The index of the first browse result associated with the element.</param>
        /// <returns></returns>
        private bool UpdateBrowseElement(
            BrowseElement element,
            BrowseDescriptionCollection nodesToBrowse,
            BrowseResultCollection results,
            int first)
        {
            // check for a valid range within the collection.
            if (first < 0 || first >= nodesToBrowse.Count)
            {
                return false;
            }

            bool missingReferences = false;

            // process all references.
            Dictionary<string,ReferenceDescription> referencesByName = new Dictionary<string, ReferenceDescription>();
            Dictionary<string,ReferenceDescription> duplicateNames = new Dictionary<string, ReferenceDescription>();

            for (int ii = first; ii < first+2; ii++)
            {
                BrowseResult result = results[ii];

                // check for errors - rejected node id are fatal; others can be ignored.
                if (StatusCode.IsBad(result.StatusCode))
                {
                    if (result.StatusCode == StatusCodes.BadNodeIdInvalid || result.StatusCode == StatusCodes.BadNodeIdInvalid || result.StatusCode == StatusCodes.BadNodeNotInView)
                    {
                        return false;
                    }

                    missingReferences = true;
                    continue;
                }

                // eliminate duplicates and index references by browse name.
                for (int jj = 0; jj < result.References.Count; jj++)
                {
                    ReferenceDescription reference = result.References[jj];

                    // ignore off server references.
                    if (reference.NodeId == null || reference.NodeId.IsAbsolute)
                    {
                        continue;
                    }

                    // construct the browse name.
                    string browseName = m_mapper.GetLocalBrowseName(reference.BrowseName);

                    if (reference.DisplayName != null)
                    {
                        browseName = reference.DisplayName.Text;
                    }

                    // check for duplicates.
                    ReferenceDescription duplicate = null;

                    if (referencesByName.TryGetValue(browseName, out duplicate))
                    {
                        if (reference.NodeId != duplicate.NodeId)
                        {
                            duplicateNames[browseName] = duplicate;
                        }

                        continue;
                    }

                    // add to table.
                    referencesByName.Add(browseName, reference);
                }
            }

            // remove duplicates.
            foreach (string duplicateName in duplicateNames.Keys)
            {
                referencesByName.Remove(duplicateName);
            }

            // save child lookup table.
            element.ReferencesByName = referencesByName;
            element.MissingReferences = missingReferences;
            
            // update the masks.
            SetElementMasks(element);
            return true;
        }
        /// <summary>
        /// Gets the properties.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="requests">The requests.</param>
        /// <param name="propertyIds">The property ids.</param>
        /// <returns>The list of properities.</returns>
        public IList<DaProperty> GetPropertyValues(Session session, ComDaReadPropertiesRequest[] requests, params int[] propertyIds)
        {
            TraceState("GetPropertyValues", requests.Length);

            // select all supported properties if none provided
            IList<DaProperty> properties = s_SupportedProperties;

            if (propertyIds == null || propertyIds.Length == 0)
            {
                propertyIds = new int[s_SupportedProperties.Length];

                for (int ii = 0; ii < propertyIds.Length; ii++)
                {
                    propertyIds[ii] = s_SupportedProperties[ii].PropertyId;
                }
            }

            // return the descriptions that match the requested properties.
            else
            {
                properties = new DaProperty[propertyIds.Length];

                for (int ii = 0; ii < propertyIds.Length; ii++)
                {
                    for (int jj = 0; jj < s_SupportedProperties.Length; jj++)
                    {
                        if (propertyIds[ii] == s_SupportedProperties[jj].PropertyId)
                        {
                            properties[ii] = s_SupportedProperties[jj];
                            break;
                        }
                    }
                }
            }

            // build a list of elements to create.
            BrowseElement[] elements = new BrowseElement[requests.Length];
            int[] indexes = new int[requests.Length];

            BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();

            for (int ii = 0; ii < requests.Length; ii++)
            {
                BrowseElement element = null;

                // lookup element in cache.
                lock (m_lock)
                {
                    string itemId = requests[ii].ItemId;

                    if (String.IsNullOrEmpty(itemId))
                    {
                        requests[ii].Error = ResultIds.E_INVALIDITEMID;
                        elements[ii] = null;
                        continue;
                    }

                    // if (m_cache.TryGetValue(itemId, out element))
                    // {
                    //    UpdateReadPropertyRequest(requests[ii], element, propertyIds);
                    //    continue;
                    // }

                    // create a new element.
                    elements[ii] = element = new BrowseElement();
                }

                element.ItemId = requests[ii].ItemId;
                element.NodeId = m_mapper.GetRemoteNodeId(element.ItemId);

                // prepare a request to browse the children.
                indexes[ii] = PrepareBrowseElementBrowseRequest(element.NodeId, nodesToBrowse);
            }

            // check if nothing more to do.
            if (nodesToBrowse.Count == 0)
            {
                return properties;
            }

            // browse all elements at once.
            BrowseResultCollection results = Browse(session, nodesToBrowse);

            // validate results and prepare read requests.
            ReadValueIdCollection nodesToRead = new ReadValueIdCollection();

            for (int ii = 0; ii < elements.Length; ii++)
            {
                BrowseElement element = elements[ii];

                if (element == null)
                {
                    continue;
                }

                // update the element with the children found.
                if (!UpdateBrowseElement(element, nodesToBrowse, results, indexes[ii]))
                {
                    requests[ii].Error = ResultIds.E_UNKNOWNITEMID;
                    elements[ii] = null;
                    continue;
                }

                // prepare to read the properties from the server.
                indexes[ii] = PrepareBrowseElementReadRequest(
                    element.NodeId, 
                    element.ReferencesByName, 
                    nodesToRead, 
                    NodeClass.Unspecified,
                    false);
            }

            // check if nothing to do.
            if (nodesToRead.Count == 0)
            {
                return properties;
            }

            // read all child properties at once.
            DataValueCollection values = Read(session, nodesToRead);

            // process results and build final table.
            for (int ii = 0; ii < elements.Length; ii++)
            {
                BrowseElement element = elements[ii];

                if (element == null)
                {
                    continue;
                }

                // update the browse element with the property values.
                if (!UpdateBrowseElement(session.TypeTree, element, nodesToRead, values, NodeClass.Unspecified, false, indexes[ii]))
                {
                    requests[ii].Error = ResultIds.E_UNKNOWNITEMID;
                    continue;
                }

                UpdateReadPropertyRequest(requests[ii], element, propertyIds);

                // save element in cache.
                lock (m_lock)
                {
                    element.CacheTimestamp = DateTime.UtcNow;
                    m_cache[element.ItemId] = element;
                }
            }

            // return the descriptions.
            return properties;
        }
        /// <summary>
        /// Gets the property value from the browse element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="propertyId">The property id.</param>
        /// <returns>The value containing the property value.</returns>
        private DaValue GetPropertyValue(BrowseElement element, int propertyId)
        {
            DaValue value = new DaValue();
            value.Quality = OpcRcw.Da.Qualities.OPC_QUALITY_GOOD;
            value.Timestamp = element.CacheTimestamp;

            // check for objects - they only support the description property.
            if (element.NodeClass == NodeClass.Object)
            {
                switch (propertyId)
                {
                    case PropertyIds.Description: { value.Value = element.BrowseName; break; }
                    case PropertyIds.UaBrowseName: { value.Value = element.UaBrowseName; break; }
                    case PropertyIds.UaDescription: { value.Value = element.UaDescription; break; }

                    default:
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        return value;
                    }
                }

                return value;
            }

            // handle variable properties.
            switch (propertyId)
            {
                case PropertyIds.Description: { value.Value = element.BrowseName; break; }
                case PropertyIds.DataType: { value.Value = element.CanonicalDataType; break; }
                case PropertyIds.ScanRate: { value.Value = element.ScanRate; break; }
                case PropertyIds.AccessRights: { value.Value = element.AccessRights; break; }
                case PropertyIds.EuType: { value.Value = element.EuType; break; }
                case PropertyIds.EuInfo: { value.Value = element.EuInfo; break; }
                case PropertyIds.UaBuiltInType: { value.Value = (int)element.BuiltInType; break; }
                case PropertyIds.UaDataTypeId: { value.Value = element.DataTypeId; break; }
                case PropertyIds.UaValueRank: { value.Value = element.ValueRank; break; }
                case PropertyIds.UaBrowseName: { value.Value = element.UaBrowseName; break; }
                case PropertyIds.UaDescription: { value.Value = element.UaDescription; break; }

                case PropertyIds.EngineeringUnits:
                {
                    if (element.EngineeringUnits == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.EngineeringUnits;
                    value.Value = element.EngineeringUnits;
                    break;
                }

                case PropertyIds.HighEU: 
                {
                    if (element.HighEU == Double.MaxValue)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.HighEU;
                    break;
                }

                case PropertyIds.LowEU:
                {
                    if (element.LowEU == Double.MaxValue)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.LowEU;
                    break;
                }

                case PropertyIds.HighIR:
                {
                    if (element.HighIR == Double.MaxValue)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.HighIR;
                    break;
                }

                case PropertyIds.LowIR:
                {
                    if (element.LowIR == Double.MaxValue)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.LowIR;
                    break;
                }

                case PropertyIds.CloseLabel:
                {
                    if (element.CloseLabel == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.CloseLabel;
                    break;
                }

                case PropertyIds.OpenLabel:
                {
                    if (element.OpenLabel == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.OpenLabel;
                    break;
                }

                case PropertyIds.TimeZone:
                {
                    if (element.TimeZone == Int32.MaxValue)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.TimeZone;
                    break;
                }
                
                case PropertyIds.Value:
                {
                    if (element.LastValue == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.LastValue.Value;
                    break;
                }

                case PropertyIds.Quality:
                {
                    if (element.LastValue == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.LastValue.Quality;
                    break;
                }

                case PropertyIds.Timestamp:
                {
                    if (element.LastValue == null)
                    {
                        value.Error = ResultIds.E_INVALID_PID;
                        break;
                    }

                    value.Value = element.LastValue.Timestamp;
                    break;
                }

                default:
                {
                    value.Error = ResultIds.E_INVALID_PID;
                    break;
                }
            }

            return value;
        }
        /// <summary>
        /// Updates the read property request with the property values.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="element">The element.</param>
        /// <param name="propertyIds">The property ids.</param>
        private void UpdateReadPropertyRequest(ComDaReadPropertiesRequest request, BrowseElement element, int[] propertyIds)
        {
            if (element == null)
            {
                request.Error = ResultIds.E_UNKNOWNITEMID;
                return;
            }

            request.Values = new DaValue[propertyIds.Length];

            for (int ii = 0; ii < propertyIds.Length; ii++)
            {
                request.Values[ii] = GetPropertyValue(element, propertyIds[ii]);
            }
        }
        /// <summary>
        /// Creates the children of the browse element.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="parent">The parent.</param>
        /// <returns>
        /// The browse element; null if the node id does not refers to a valid element.
        /// </returns>
        private List<BrowseElement> LookupChildElements(Session session, BrowseElement parent)
        {
            List<BrowseElement> children = new List<BrowseElement>();
            List<BrowseElement> childrenToFind = new List<BrowseElement>();
            List<int> indexes = new List<int>();

            BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();

            // create an element for each child reference.
            foreach (ReferenceDescription reference in parent.ReferencesByName.Values)
            {
                NodeId nodeId = (NodeId)reference.NodeId;
                string itemId = m_mapper.GetLocalItemId(nodeId);

                BrowseElement child = null;

                lock (m_lock)
                {
                    // check if child has already been cached.
                    if (m_cache.TryGetValue(itemId, out child))
                    {
                        child.ParentId = parent.ItemId;
                        children.Add(child);
                        continue;
                    }

                    // create a new element.
                    child = new BrowseElement();
                }

                child.NodeId = nodeId;
                child.ItemId = itemId;
                child.NodeClass = reference.NodeClass;
                child.BrowseName = child.UaBrowseName = m_mapper.GetLocalBrowseName(reference.BrowseName);

                if (reference.DisplayName != null)
                {
                    child.BrowseName = reference.DisplayName.Text;
                }

                int index = PrepareBrowseElementBrowseRequest(child.NodeId, nodesToBrowse);

                childrenToFind.Add(child);
                indexes.Add(index);
            }

            // check if nothing to do because everything was in the cache.
            if (childrenToFind.Count == 0)
            {
                return children;
            }

            // browse all elements at once.
            BrowseResultCollection results = Browse(session, nodesToBrowse);

            // validate results and prepare read requests.
            ReadValueIdCollection nodesToRead = new ReadValueIdCollection();

            for (int ii = 0; ii < childrenToFind.Count; ii++)
            {
                BrowseElement child = childrenToFind[ii];

                // update the element with the children found.
                if (!UpdateBrowseElement(child, nodesToBrowse, results, indexes[ii]))
                {
                    children[ii] = null;
                    continue;
                }

                // all done with objects.
                if (child.NodeClass == NodeClass.Object)
                {
                    child.ParentId = parent.ItemId;
                    children.Add(child);

                    lock (m_lock)
                    {
                        child.CacheTimestamp = DateTime.UtcNow;
                        m_cache[child.ItemId] = child;
                    }
                }

                // prepare to read the properties from the server.
                indexes[ii] = PrepareBrowseElementReadRequest(child.NodeId, child.ReferencesByName, nodesToRead, child.NodeClass, true);
            }

            // check if nothing to do because only objects with no properties..
            if (nodesToRead.Count == 0)
            {
                return children;
            }

            // read all child properties at once.
            DataValueCollection values = Read(session, nodesToRead);

            // process results and build final table.
            for (int ii = 0; ii < childrenToFind.Count; ii++)
            {
                BrowseElement child = childrenToFind[ii];

                if (child == null || child.NodeClass == NodeClass.Object)
                {
                    continue;
                }

                // update the browse element with the property values.
                if (!UpdateBrowseElement(session.TypeTree, child, nodesToRead, values, child.NodeClass, true, indexes[ii]))
                {
                    continue;
                }

                // add variables to the cache.
                child.ParentId = parent.ItemId;
                children.Add(child);

                lock (m_lock)
                {
                    child.CacheTimestamp = DateTime.UtcNow;
                    m_cache[child.ItemId] = child;
                }
            }

            return children;
        }