private unsafe Guid GetPropertyPage(Ole32.DispatchID dispid)
            {
                try
                {
                    Ole32.IPerPropertyBrowsing ippb = owner.GetPerPropertyBrowsing();
                    if (ippb == null)
                    {
                        return(Guid.Empty);
                    }

                    Guid rval = Guid.Empty;
                    if (ippb.MapPropertyToPage(dispid, &rval).Succeeded())
                    {
                        return(rval);
                    }
                }
                catch (COMException)
                {
                }
                catch (Exception t)
                {
                    Debug.Fail(t.ToString());
                }
                return(Guid.Empty);
            }
        internal static string GetDisplayString(Ole32.IPerPropertyBrowsing ppb, Ole32.DispatchID dispid, ref bool success)
        {
            HRESULT hr = ppb.GetDisplayString(dispid, out string strVal);

            if (hr != HRESULT.S_OK)
            {
                success = false;
                return(null);
            }

            success = strVal != null;
            return(strVal);
        }
        private unsafe Guid GetPropertyPageGuid(Ole32.IPerPropertyBrowsing target, Ole32.DispatchID dispid)
        {
            // check for a property page
            Guid    guid = Guid.Empty;
            HRESULT hr   = target.MapPropertyToPage(dispid, &guid);

            if (hr == HRESULT.S_OK)
            {
                return(guid);
            }

            return(Guid.Empty);
        }
            /*internal bool StandardValuesQueried {
             * get {
             *     this.standardValuesQueried = value;
             * }
             * } */

            // ensure that we have processed the caStructs into arrays
            // of values and strings
            //
            private void EnsureArrays()
            {
                if (arraysFetched)
                {
                    return;
                }

                arraysFetched = true;

                try
                {
                    // marshal the items.
                    object[] nameItems   = nameMarshaller.Items;
                    object[] cookieItems = valueMarshaller.Items;

                    Ole32.IPerPropertyBrowsing ppb = (Ole32.IPerPropertyBrowsing)target.TargetObject;
                    int itemCount = 0;

                    Debug.Assert(cookieItems != null && nameItems != null, "An item array is null");

                    if (nameItems.Length > 0)
                    {
                        object[] valueItems = new object[cookieItems.Length];
                        var      var        = new Ole32.VARIANT();
                        int      cookie;

                        Debug.Assert(cookieItems.Length == nameItems.Length, "Got uneven names and cookies");

                        // for each name item, we ask the object for it's corresponding value.
                        //
                        Type targetType = target.PropertyType;
                        for (int i = nameItems.Length - 1; i >= 0; i--)
                        {
                            cookie = (int)cookieItems[i];
                            if (nameItems[i] == null || !(nameItems[i] is string))
                            {
                                Debug.Fail("Bad IPerPropertyBrowsing item [" + i.ToString(CultureInfo.InvariantCulture) + "], name=" + (nameItems == null ? "(unknown)" : nameItems[i].ToString()));
                                continue;
                            }
                            var.vt = Ole32.VARENUM.EMPTY;
                            HRESULT hr = ppb.GetPredefinedValue(target.DISPID, (uint)cookie, var);
                            if (hr == HRESULT.S_OK && var.vt != Ole32.VARENUM.EMPTY)
                            {
                                valueItems[i] = var.ToObject();
                                if (valueItems[i].GetType() != targetType)
                                {
                                    if (targetType.IsEnum)
                                    {
                                        valueItems[i] = Enum.ToObject(targetType, valueItems[i]);
                                    }
                                    else
                                    {
                                        try
                                        {
                                            valueItems[i] = Convert.ChangeType(valueItems[i], targetType, CultureInfo.InvariantCulture);
                                        }
                                        catch
                                        {
                                            // oh well...
                                        }
                                    }
                                }
                            }

                            var.Clear();
                            if (hr == NativeMethods.S_OK)
                            {
                                itemCount++;
                                continue;
                            }
                            else if (itemCount > 0)
                            {
                                // shorten the arrays to ignore the failed ones.  this isn't terribly
                                // efficient but shouldn't happen very often.  It's rare for these to fail.
                                //
                                Array.Copy(nameItems, i, nameItems, i + 1, itemCount);
                                Array.Copy(valueItems, i, valueItems, i + 1, itemCount);
                            }
                        }

                        // pass this data down to the base Com2Enum object...
                        string[] strings = new string[itemCount];
                        Array.Copy(nameItems, 0, strings, 0, itemCount);
                        base.PopulateArrays(strings, valueItems);
                    }
                }
                catch (Exception ex)
                {
                    base.PopulateArrays(Array.Empty <string>(), Array.Empty <object>());
                    Debug.Fail("Failed to build IPerPropertyBrowsing editor. " + ex.GetType().Name + ", " + ex.Message);
                }
            }
            /// <summary>
            ///  Called externally to update the editor or type converter.
            ///  This simply sets flags so this will happen, it doesn't actually to the update...
            ///  we wait and do that on-demand for perf.
            /// </summary>
            internal unsafe void UpdateTypeConverterAndTypeEditorInternal(bool force, Ole32.DispatchID dispid)
            {
                // check to see if we're being forced here or if the work really
                // needs to be done.
                //
                if (GetFlag(FlagUpdatedEditorAndConverter) && !force)
                {
                    return;
                }

                if (owner.GetOcx() == null)
                {
                    return;
                }

                try
                {
                    Ole32.IPerPropertyBrowsing ppb = owner.GetPerPropertyBrowsing();

                    if (ppb != null)
                    {
                        bool hasStrings = false;

                        // check for enums
                        var caStrings = new Ole32.CA_STRUCT();
                        var caCookies = new Ole32.CA_STRUCT();

                        HRESULT hr = HRESULT.S_OK;
                        try
                        {
                            hr = ppb.GetPredefinedStrings(dispid, &caStrings, &caCookies);
                        }
                        catch (ExternalException ex)
                        {
                            hr = (HRESULT)ex.ErrorCode;
                            Debug.Fail("An exception occurred inside IPerPropertyBrowsing::GetPredefinedStrings(dispid=" +
                                       dispid + "), object type=" + new ComNativeDescriptor().GetClassName(ppb));
                        }

                        if (hr != HRESULT.S_OK)
                        {
                            hasStrings = false;
                            // Destroy the existing editor if we created the current one
                            // so if the items have disappeared, we don't hold onto the old
                            // items.
                            if (converter is Com2EnumConverter)
                            {
                                converter = null;
                            }
                        }
                        else
                        {
                            hasStrings = true;
                        }

                        if (hasStrings)
                        {
                            OleStrCAMarshaler stringMarshaler = new OleStrCAMarshaler(caStrings);
                            Int32CAMarshaler  intMarshaler    = new Int32CAMarshaler(caCookies);

                            if (stringMarshaler.Count > 0 && intMarshaler.Count > 0)
                            {
                                if (converter == null)
                                {
                                    converter = new AxEnumConverter(this, new AxPerPropertyBrowsingEnum(this, owner, stringMarshaler, intMarshaler, true));
                                }
                                else if (converter is AxEnumConverter)
                                {
                                    ((AxEnumConverter)converter).RefreshValues();
                                    if (((AxEnumConverter)converter).com2Enum is AxPerPropertyBrowsingEnum axEnum)
                                    {
                                        axEnum.RefreshArrays(stringMarshaler, intMarshaler);
                                    }
                                }
                            }
                            else
                            {
                                //hasStrings = false;
                            }
                        }
                        else
                        {
                            // if we didn't get any strings, try the proppage edtior
                            //
                            // Check to see if this is a property that we have already massaged to be a
                            // .Net type. If it is, don't bother with custom property pages. We already
                            // have a .Net Editor for this type.
                            //
                            ComAliasNameAttribute comAlias = (ComAliasNameAttribute)baseProp.Attributes[typeof(ComAliasNameAttribute)];
                            if (comAlias == null)
                            {
                                Guid g = GetPropertyPage(dispid);

                                if (!Guid.Empty.Equals(g))
                                {
                                    editor = new AxPropertyTypeEditor(this, g);

                                    // Show any non-browsable property that has an editor through a
                                    // property page.
                                    //
                                    if (!IsBrowsable)
                                    {
                                        Debug.WriteLineIf(AxPropTraceSwitch.TraceVerbose, "Making property: " + Name + " browsable because we found an editor.");
                                        AddAttribute(new BrowsableAttribute(true));
                                    }
                                }
                            }
                        }
                    }

                    SetFlag(FlagUpdatedEditorAndConverter, true);
                }
                catch (Exception e)
                {
                    Debug.WriteLineIf(AxPropTraceSwitch.TraceVerbose, "could not get the type editor for property: " + Name + " Exception: " + e);
                }
            }
            // ensure that we have processed the caStructs into arrays
            // of values and strings
            //
            private void EnsureArrays()
            {
                if (arraysFetched)
                {
                    return;
                }

                arraysFetched = true;

                try
                {
                    // marshal the items.
                    object[] nameItems             = nameMarshaller.Items;
                    object[] cookieItems           = valueMarshaller.Items;
                    Ole32.IPerPropertyBrowsing ppb = (Ole32.IPerPropertyBrowsing)owner.GetPerPropertyBrowsing();
                    int itemCount = 0;

                    Debug.Assert(cookieItems != null && nameItems != null, "An item array is null");

                    if (nameItems.Length > 0)
                    {
                        object[] valueItems = new object[cookieItems.Length];
                        var      var        = new Ole32.VARIANT();
                        int      cookie;

                        Debug.Assert(cookieItems.Length == nameItems.Length, "Got uneven names and cookies");

                        // for each name item, we ask the object for it's corresponding value.
                        //
                        for (int i = 0; i < nameItems.Length; i++)
                        {
                            cookie = (int)cookieItems[i];
                            if (nameItems[i] == null || !(nameItems[i] is string))
                            {
                                Debug.Fail("Bad IPerPropertyBrowsing item [" + i.ToString(CultureInfo.InvariantCulture) + "], name=" + (nameItems == null ? "(unknown)" : nameItems[i].ToString()));
                                continue;
                            }
                            var.vt = (short)Ole32.VARENUM.EMPTY;
                            HRESULT hr = ppb.GetPredefinedValue(target.Dispid, (uint)cookie, var);
                            if (hr == HRESULT.S_OK && var.vt != Ole32.VARENUM.EMPTY)
                            {
                                valueItems[i] = var.ToObject();
                            }
                            var.Clear();
                            itemCount++;
                        }

                        // pass this data down to the base Com2Enum object...
                        if (itemCount > 0)
                        {
                            string[] strings = new string[itemCount];
                            Array.Copy(nameItems, 0, strings, 0, itemCount);
                            base.PopulateArrays(strings, valueItems);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug.Fail("Failed to build IPerPropertyBrowsing editor. " + ex.GetType().Name + ", " + ex.Message);
                }
            }