Beispiel #1
0
    public Data()
    {
        list.Add(5);
        list.Add(2);
        list.Add(1);
        list.Add(8);

        refB = refA;
    }
Beispiel #2
0
        internal void AssignHandle(IntPtr handle, bool assignUniqueID)
        {
            lock (this)
            {
                CheckReleased();
                Debug.Assert(handle != IntPtr.Zero, "handle is 0");

                Handle = handle;

                _priorWindowProcHandle = User32.GetWindowLong(this, User32.GWL.WNDPROC);
                Debug.Assert(_priorWindowProcHandle != IntPtr.Zero);

                Debug.WriteLineIf(
                    WndProcChoice.TraceVerbose,
                    WndProcShouldBeDebuggable ? "Using debuggable wndproc" : "Using normal wndproc");

                _windowProc = new User32.WNDPROC(Callback);

                AddWindowToTable(handle, this);

                // Set the NativeWindow window procedure delegate and get back the native pointer for it.
                User32.SetWindowLong(this, User32.GWL.WNDPROC, _windowProc);
                _windowProcHandle = User32.GetWindowLong(this, User32.GWL.WNDPROC);

                // This shouldn't be possible.
                Debug.Assert(_priorWindowProcHandle != _windowProcHandle, "Uh oh! Subclassed ourselves!!!");

                if (assignUniqueID &&
                    ((User32.WS)PARAM.ToUInt(User32.GetWindowLong(this, User32.GWL.STYLE))).HasFlag(User32.WS.CHILD) &&
                    User32.GetWindowLong(this, User32.GWL.ID) == IntPtr.Zero)
                {
                    User32.SetWindowLong(this, User32.GWL.ID, handle);
                }

                if (_suppressedGC)
                {
                    GC.ReRegisterForFinalize(this);
                    _suppressedGC = false;
                }

                OnHandleChange();
            }
        }
Beispiel #3
0
            protected override void WndProc(ref Message m)
            {
                if (_designer is null)
                {
                    DefWndProc(ref m);
                    return;
                }

                if (m.Msg == (int)User32.WM.DESTROY)
                {
                    _designer.RemoveSubclassedWindow(m.HWnd);
                }

                if (m.Msg == (int)User32.WM.PARENTNOTIFY && PARAM.LOWORD(m.WParam) == (short)User32.WM.CREATE)
                {
                    _designer.HookChildHandles(m.LParam); // they will get removed from the collection just above
                }

                // We want these messages to go through the designer's WndProc method, and we want people to be able
                // to do default processing with the designer's DefWndProc.  So, we stuff ourselves into the designers
                // window target and call their WndProc.
                IDesignerTarget designerTarget = _designer.DesignerTarget;

                _designer.DesignerTarget = this;
                Debug.Assert(m.HWnd == Handle, "Message handle differs from target handle");

                try
                {
                    _designer.WndProc(ref m);
                }
                catch (Exception ex)
                {
                    _designer.SetUnhandledException(Control.FromChildHandle(m.HWnd), ex);
                }
                finally
                {
                    // make sure the designer wasn't destroyed
                    if (_designer != null && _designer.Component != null)
                    {
                        _designer.DesignerTarget = designerTarget;
                    }
                }
            }
Beispiel #4
0
        public void TextBox_PlaceholderTextAlignmentsInRightToLeft()
        {
            using var tb = new TextBox
                  {
                      PlaceholderText = "Enter your name",
                      RightToLeft     = RightToLeft.Yes
                  };

            HandleRef refHandle = new HandleRef(tb, tb.Handle);

            //Cover the Placeholder draw code path in RightToLeft scenario
            User32.SendMessageW(refHandle, User32.WM.PAINT, PARAM.FromBool(false));
            tb.TextAlign = HorizontalAlignment.Center;
            User32.SendMessageW(refHandle, User32.WM.PAINT, PARAM.FromBool(false));
            tb.TextAlign = HorizontalAlignment.Right;
            User32.SendMessageW(refHandle, User32.WM.PAINT, PARAM.FromBool(false));

            Assert.False(string.IsNullOrEmpty(tb.PlaceholderText));
        }
Beispiel #5
0
        private void UpdateHelmetWorkStations(DoorDbContext context)
        {
            PARAM helmetParam1 = new PARAM();

            helmetParam1.Domain = HelmetTypes.Domain;
            helmetParam1.Label  = HelmetTypes.StandartType;
            helmetParam1.Value  = HelmetTypes.StandartTypeValue;

            HelmetWorkStation station1 = new HelmetWorkStation();

            station1.HelmetType        = helmetParam1;
            station1.WorkStationNumber = 1;


            context.HelmetWorkStations.Add(station1);

            HelmetWorkStation station3 = new HelmetWorkStation();

            station3.HelmetType        = helmetParam1;
            station3.WorkStationNumber = 3;

            context.HelmetWorkStations.Add(station3);

            PARAM helmetParam2 = new PARAM();

            helmetParam2.Domain = HelmetTypes.Domain;
            helmetParam2.Label  = HelmetTypes.PremiumType;
            helmetParam2.Value  = HelmetTypes.PremiumTypeValue;

            HelmetWorkStation station2 = new HelmetWorkStation();

            station2.HelmetType        = helmetParam2;
            station2.WorkStationNumber = 2;
            context.HelmetWorkStations.Add(station2);

            HelmetWorkStation station4 = new HelmetWorkStation();

            station4.HelmetType        = helmetParam2;
            station4.WorkStationNumber = 4;

            context.HelmetWorkStations.Add(station4);
        }
Beispiel #6
0
        public static void addParam(SiapTable vot, dataType dt, string name, string desc, int ind)
        {
            PARAM p = new PARAM();

            p.name        = name;
            p.DESCRIPTION = new anyTEXT();
            p.datatype    = dt;
            if (dt == dataType.@char)
            {
                p.arraysize = "*";
            }

            p.DESCRIPTION.Any = new System.Xml.XmlNode[1];
            XmlDocument doc = new XmlDocument();

            p.DESCRIPTION.Any[0] = doc.CreateTextNode("DESCRIPTION");

            p.DESCRIPTION.Any[0].InnerText = desc;
            vot.RESOURCE[0].Items[ind]     = p;
        }
Beispiel #7
0
        private static PARAM GetParam(BND4 parambnd, string paramfile)
        {
            var bndfile = parambnd.Files.Find(x => Path.GetFileName(x.Name) == paramfile);

            if (bndfile != null)
            {
                return(PARAM.Read(bndfile.Bytes));
            }

            // Otherwise the param is a loose param
            if (File.Exists($@"{AssetLocator.GameModDirectory}\Param\{paramfile}"))
            {
                return(PARAM.Read($@"{AssetLocator.GameModDirectory}\Param\{paramfile}"));
            }
            if (File.Exists($@"{AssetLocator.GameRootDirectory}\Param\{paramfile}"))
            {
                return(PARAM.Read($@"{AssetLocator.GameRootDirectory}\Param\{paramfile}"));
            }
            return(null);
        }
            private int DisplayIndexToID(int displayIndex)
            {
                Debug.Assert(!owner.VirtualMode, "in virtual mode, this method does not make any sense");
                if (owner.IsHandleCreated && !owner.ListViewHandleDestroyed)
                {
                    // Obtain internal index of the item
                    var lvItem = new LVITEMW
                    {
                        mask  = LVIF.PARAM,
                        iItem = displayIndex
                    };

                    User32.SendMessageW(owner, (User32.WM)LVM.GETITEMW, 0, ref lvItem);
                    return(PARAM.ToInt(lvItem.lParam));
                }
                else
                {
                    return(this[displayIndex].ID);
                }
            }
Beispiel #9
0
        public static List <PARAM.Row> GetMatchingParamRowsByPropRef(PARAM param, string rowfield, string namerx, bool lenient, bool failureAllOrNone)
        {
            List <PARAM.Row> rlist = new List <PARAM.Row>();

            try
            {
                Regex rownamerx = lenient ? new Regex(namerx.ToLower()) : new Regex($@"^{namerx}$");
                foreach (PARAM.Row row in param.Rows)
                {
                    PARAM.Cell c = row[rowfield.Replace(@"\s", " ")];
                    if (c == null)
                    {
                        continue;
                    }
                    int val = (int)c.Value;
                    foreach (string rt in FieldMetaData.Get(c.Def).RefTypes)
                    {
                        if (!ParamBank.Params.ContainsKey(rt))
                        {
                            continue;
                        }
                        PARAM.Row r = ParamBank.Params[rt][val];
                        if (r == null)
                        {
                            continue;
                        }
                        string nameToMatch = r.Name == null ? "" : r.Name;
                        if (r != null && rownamerx.Match(lenient ? nameToMatch.ToLower() : nameToMatch).Success)
                        {
                            rlist.Add(row);
                            break;
                        }
                    }
                }
                return(rlist);
            }
            catch
            {
                return(failureAllOrNone ? param.Rows : rlist);
            }
        }
Beispiel #10
0
 protected void Gridview2_RowDeleting(object sender, GridViewDeleteEventArgs e)
 {
     this.PanelNewUser.CssClass  = "content-box column-left";
     this.PanelEditUser.CssClass = "content-box column-right closed-box";
     try
     {
         string       TittleText = ((TextBox)this.Gridview2.Rows[e.RowIndex].FindControl("EditTittle")).Text;
         string       DescText   = ((TextBox)this.Gridview2.Rows[e.RowIndex].FindControl("EditDescription")).Text;
         List <PARAM> list       = (List <PARAM>) this.Application["Params"];
         PARAM        obj        = Enumerable.Single <PARAM>((IEnumerable <PARAM>)list, (Func <PARAM, bool>)(p => p.Description == DescText && p.Tittle == TittleText));
         list.Remove(obj);
         this.Gridview2.DataSource = (object)list;
         this.Gridview2.DataBind();
         this.Application["Params"] = (object)list;
     }
     catch
     {
         this.Gridview2.DataSource = (object)(List <PARAM>) this.Application["Params"];
         this.Gridview2.DataBind();
     }
 }
Beispiel #11
0
 // Load params from given path, relative to current dir
 public Dictionary <string, PARAM> LoadParams(string path, Dictionary <string, PARAM.Layout> layouts = null, bool allowError = false)
 {
     layouts = layouts ?? LoadLayouts();
     return(LoadBnd(path, (data, paramPath) =>
     {
         PARAM param;
         try
         {
             param = PARAM.Read(data);
         }
         catch (Exception e)
         {
             if (!allowError)
             {
                 throw new Exception($"Failed to load param {paramPath}: " + e);
             }
             // For DS3 this also includes draw params, so just silently fail
             // TODO: Find a better way to load all params reliably
             return null;
         }
         if (layouts == null)
         {
             return param;
         }
         else if (layouts.ContainsKey(param.ParamType))
         {
             PARAM.Layout layout = layouts[param.ParamType];
             if (layout.Size == param.DetectedSize)
             {
                 param.ApplyParamdef(layout.ToParamdef(param.ParamType, out var _));
                 return param;
             }
             else
             {
                 // Console.WriteLine($"Mismatched size for {path} - {layout.Size} vs {param.DetectedSize} actual");
             }
         }
         return null;
     }));
 }
Beispiel #12
0
        public PARAM Read(string name, PARAMDEF def)
        {
            var worksheet = Spreadsheet.Workbook.Worksheets.First(sheet => sheet.Name.Equals(name));
            var rowCount  = worksheet.Dimension.Rows;

            var param = new PARAM();

            param.ParamType = def.ParamType;
            param.Rows      = new List <PARAM.Row>(rowCount - 2);
            param.ApplyParamdef(def);

            for (var rowIndex = 3; rowIndex <= rowCount; rowIndex++)
            {
                var id      = int.Parse(worksheet.Cells[rowIndex, 1].Value.ToString());
                var rowName = worksheet.Cells[rowIndex, 2].Value ?? string.Empty;
                var row     = new PARAM.Row(id, (string?)rowName, def);

                for (var cellIndex = 0; cellIndex < def.Fields.Count; cellIndex++)
                {
                    var value = worksheet.Cells[rowIndex, 3 + cellIndex].Value;
                    if (value is string v && v == "-")
                    {
                        // padding, we don't store this in excel files
                        continue;
                    }

                    if (value is null)
                    {
                        Console.WriteLine($"Row ID {id} and field ${def.Fields[cellIndex].DisplayName} has null value, assuming default");
                        continue;
                    }

                    row.Cells[cellIndex].Value = value;
                }

                param.Rows.Add(row);
            }

            return(param);
        }
Beispiel #13
0
        public static List <PARAM.Row> GetMatchingParamRowsByID(PARAM param, string rowvalexp, bool lenient, bool failureAllOrNone)
        {
            List <PARAM.Row> rlist = new List <PARAM.Row>();

            try
            {
                Regex rx = lenient ? new Regex(rowvalexp) : new Regex($@"^{rowvalexp}$");
                foreach (PARAM.Row row in param.Rows)
                {
                    string term = row.ID.ToString();
                    if (rx.Match(term).Success)
                    {
                        rlist.Add(row);
                    }
                }
                return(rlist);
            }
            catch
            {
                return(failureAllOrNone ? param.Rows : rlist);
            }
        }
        public bool SerializeDS2Regist(PARAM regist)
        {
            HashSet <long> ids = new HashSet <long>();

            foreach (var o in Objects)
            {
                if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2GeneratorRegist && m.WrappedObject is PARAM.Row mp)
                {
                    if (!ids.Contains(mp.ID))
                    {
                        ids.Add(mp.ID);
                    }
                    else
                    {
                        MessageBox.Show($@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    regist.Rows.Add(mp);
                }
            }
            return(true);
        }
Beispiel #15
0
        public static List <PARAM.Row> GetMatchingParamRowsByName(PARAM param, string namerx, bool lenient, bool failureAllOrNone)
        {
            List <PARAM.Row> rlist = new List <PARAM.Row>();

            try
            {
                Regex rownamerx = lenient ? new Regex(namerx.ToLower()) : new Regex($@"^{namerx}$");
                foreach (PARAM.Row row in param.Rows)
                {
                    string nameToMatch = row.Name == null ? "" : row.Name;
                    if (rownamerx.Match(lenient ? nameToMatch.ToLower() : nameToMatch).Success)
                    {
                        rlist.Add(row);
                    }
                }
                return(rlist);
            }
            catch
            {
                return(failureAllOrNone ? param.Rows : rlist);
            }
        }
Beispiel #16
0
        protected override bool ProcessKeyEventArgs(ref Message m)
        {
            switch ((Keys)PARAM.ToInt(m.WParam))
            {
            case Keys.Enter:
                if (m.Msg == (int)User32.WM.CHAR &&
                    !(ModifierKeys == Keys.Shift && Multiline && AcceptsReturn))
                {
                    // Ignore the Enter key and don't add it to the textbox content. This happens when failing validation brings
                    // up a dialog box for example.
                    // Shift-Enter for multiline textboxes need to be accepted however.
                    return(true);
                }

                break;

            case Keys.LineFeed:
                if (m.Msg == (int)User32.WM.CHAR &&
                    ModifierKeys == Keys.Control && Multiline && AcceptsReturn)
                {
                    // Ignore linefeed character when user hits Ctrl-Enter to commit the cell.
                    return(true);
                }

                break;

            case Keys.A:
                if (m.Msg == (int)User32.WM.KEYDOWN && ModifierKeys == Keys.Control)
                {
                    SelectAll();
                    return(true);
                }

                break;
            }

            return(base.ProcessKeyEventArgs(ref m));
        }
            public ParamFile(string name, PARAM param, Dictionary <string, PARAM.Layout> layouts)
            {
                Name  = name;
                Param = param;
                string format = Param.ParamType;

                if (!layouts.ContainsKey(format))
                {
                    layouts[format] = new PARAM.Layout();
                }

                try
                {
                    Layout = layouts[format];
                    Param.ApplyParamdef(Layout.ToParamdef(param.ParamType, out _));
                    Rows = Param.Rows;
                }
                catch (Exception ex)
                {
                    Rows = new List <PARAM.Row>();
                    ShowError($"Error in layout {format}, please try again.\r\n\r\n{ex}");
                }
            }
        public ParamWrapper(string name, PARAM param, PARAM.Layout layout, string description)
        {
            if (layout.Size != param.DetectedSize)
            {
                Console.WriteLine(name);
                Console.WriteLine(layout.Size);
                Console.WriteLine(param.DetectedSize);
                Console.WriteLine(param.DetectedSize - layout.Size);
            }

            if (layout == null || layout.Size != param.DetectedSize)
            {
                layout = new PARAM.Layout();
                layout.Add(new PARAM.Layout.Entry(PARAM.CellType.dummy8, "Unknown", (int)param.DetectedSize, null));
                Error = true;
            }

            Name   = name;
            Param  = param;
            Layout = layout;
            Param.SetLayout(layout);
            Description = description;
        }
Beispiel #19
0
 private static void LoadParamFromBinder(IBinder parambnd)
 {
     // Load every param in the regulation
     //_params = new Dictionary<string, PARAM>();
     foreach (var f in parambnd.Files)
     {
         if (!f.Name.ToUpper().EndsWith(".PARAM") || Path.GetFileNameWithoutExtension(f.Name).StartsWith("default_"))
         {
             continue;
         }
         if (f.Name.EndsWith("LoadBalancerParam.param"))
         {
             continue;
         }
         if (_params.ContainsKey(Path.GetFileNameWithoutExtension(f.Name)))
         {
             continue;
         }
         PARAM p = PARAM.Read(f.Bytes);
         p.ApplyParamdef(_paramdefs[p.ParamType]);
         _params.Add(Path.GetFileNameWithoutExtension(f.Name), p);
     }
 }
        public static List <PARAM.Row> GetMatchingParamRowsByPropVal(PARAM param, string rowfield, string rowvalexp, bool lenient, bool failureAllOrNone)
        {
            List <PARAM.Row> rlist = new List <PARAM.Row>();

            try
            {
                Regex rx = new Regex(rowvalexp);
                foreach (PARAM.Row row in param.Rows)
                {
                    PARAM.Cell c    = row[rowfield];
                    string     term = lenient ? $@".*{c.Value.ToString()}.*" : c.Value.ToString();
                    if (c != null && rx.Match(term).Success)
                    {
                        rlist.Add(row);
                    }
                }
                return(rlist);
            }
            catch
            {
                return(failureAllOrNone ? param.Rows : rlist);
            }
        }
Beispiel #21
0
        private void UnpackGameBNDFile()
        {
            // Reading an original paramdefbnd
            paramDefs   = new Dictionary <string, PARAMDEF>();
            paramDefBnd = BND3.Read(pathToParamDef);

            foreach (BinderFile file in paramDefBnd.Files)
            {
                var paramdef = PARAMDEF.Read(file.Bytes);
                paramDefs[paramdef.ParamType] = paramdef;
            }

            parms    = new Dictionary <string, PARAM>();
            paramBnd = BND3.Read(pathToParamDataFile);

            foreach (BinderFile file in paramBnd.Files)
            {
                string name  = Path.GetFileNameWithoutExtension(file.Name);
                var    param = PARAM.Read(file.Bytes);
                param.ApplyParamdef(paramDefs[param.ParamType]);
                parms[name] = param;
            }
        }
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == (int)User32.WM.SHOWWINDOW)
                {
                    return;
                }

                base.WndProc(ref m);
                switch (m.Msg)
                {
                case (int)User32.WM.PARENTNOTIFY:
                    if (PARAM.LOWORD(m.WParam) == (int)User32.WM.DESTROY)
                    {
                        User32.PostMessageW(this, (User32.WM)WM_CHECKDESTROY);
                    }

                    break;

                case WM_CHECKDESTROY:
                    CheckDestroy();
                    break;
                }
            }
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WindowMessages.WM_SHOWWINDOW)
                {
                    return;
                }

                base.WndProc(ref m);
                switch (m.Msg)
                {
                case WindowMessages.WM_PARENTNOTIFY:
                    if (PARAM.LOWORD(m.WParam) == WindowMessages.WM_DESTROY)
                    {
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), WM_CHECKDESTROY, IntPtr.Zero, IntPtr.Zero);
                    }

                    break;

                case WM_CHECKDESTROY:
                    CheckDestroy();
                    break;
                }
            }
        public bool SerializeDS2Generators(PARAM locations, PARAM generators)
        {
            HashSet <long> ids = new HashSet <long>();

            foreach (var o in Objects)
            {
                if (o is MapEntity m && m.Type == MapEntity.MapEntityType.DS2Generator && m.WrappedObject is MergedParamRow mp)
                {
                    if (!ids.Contains(mp.ID))
                    {
                        ids.Add(mp.ID);
                    }
                    else
                    {
                        MessageBox.Show($@"{mp.Name} has an ID that's already used. Please change it to something unique and save again.", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    var loc = mp.GetRow("generator-loc");
                    if (loc != null)
                    {
                        // Adjust the location to be relative to the mapoffset
                        var newloc = new PARAM.Row(loc);
                        newloc["PositionX"].Value = (float)loc["PositionX"].Value - MapOffset.Position.X;
                        newloc["PositionY"].Value = (float)loc["PositionY"].Value - MapOffset.Position.Y;
                        newloc["PositionZ"].Value = (float)loc["PositionZ"].Value - MapOffset.Position.Z;
                        locations.Rows.Add(newloc);
                    }
                    var gen = mp.GetRow("generator");
                    if (gen != null)
                    {
                        generators.Rows.Add(gen);
                    }
                }
            }
            return(true);
        }
Beispiel #25
0
    /******************************
    ******************************/
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha0))
        {
            Debug.Log("Weight=" + StrTest[0, 0].get_Weight() + ", ");

            SampleDelegate dele = StrTest[0, 0].get_SampleDelegate();
            dele(0);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            Debug.Log("Weight=" + StrTest[0, 1].get_Weight() + ", ");

            SampleDelegate dele;
            StrTest[0, 1].Copy_SampleDelegate(out dele);
            dele(0);
        }
        else if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            PARAM param = StrTest[0, 0].get_PARAM();
            // param.val = 99; // readonlyなのでCompile Error.
            StrTest[0, 0].print_param();
        }
    }
        public void InitiateWindowDrag(IntPtr hWnd, IntPtr lParam)
        {
            if (_dragWindowInfo != null)
            {
                ReleaseCapture();
                _dragWindowInfo.Reset();

                var dragPoint = new POINT();
                dragPoint.x = PARAM.SignedLOWORD(lParam);
                dragPoint.y = PARAM.SignedHIWORD(lParam);

                var windowTopLeftPoint = new POINT();
                if (_dragWindowInfo.IsCursorInDraggableRegion(ref dragPoint, ref windowTopLeftPoint))
                {
                    SetCapture(hWnd);

                    _dragWindowInfo.DragInitiated      = true;
                    _dragWindowInfo.DragPoint          = dragPoint;
                    _dragWindowInfo.DragWindowLocation = windowTopLeftPoint;

                    InstallDragMouseHook();
                }
            }
        }
Beispiel #27
0
        public static void TriggerDpiMessage(User32.WM message, Control control, int newDpi)
        {
            double factor = newDpi / DpiHelper.LogicalDpi;
            IntPtr wParam = PARAM.FromLowHigh(newDpi, newDpi);

            _ = message switch
            {
                User32.WM.DPICHANGED => SendWmDpiChangedMessage(),
                User32.WM.DPICHANGED_BEFOREPARENT => User32.SendMessageW(control, message, wParam),
                User32.WM.DPICHANGED_AFTERPARENT => User32.SendMessageW(control, message),
                _ => throw new NotImplementedException()
            };

            IntPtr SendWmDpiChangedMessage()
            {
                RECT suggestedRect = new(0,
                                         0,
                                         (int)Math.Round(control.Width * factor),
                                         (int)Math.Round(control.Height * factor));

                return(User32.SendMessageW(control, message, wParam, ref suggestedRect));
            }
        }
    }
            private int GetCharIndexFromPosition(Point pt)
            {
                int index = (int)User32.SendMessageW(_owningChildEdit, (WM)EM.CHARFROMPOS, 0, PARAM.FromPoint(pt));

                index = PARAM.LOWORD(index);

                if (index < 0)
                {
                    index = 0;
                }
                else
                {
                    string t = Text;
                    // EM_CHARFROMPOS will return an invalid number if the last character in the RichEdit
                    // is a newline.
                    //
                    if (index >= t.Length)
                    {
                        index = Math.Max(t.Length - 1, 0);
                    }
                }

                return(index);
            }
 void Test_Util_Parameter()
 {
     string s = new PARAM("field").ToString();
 }
        private SortedDictionary <int, List <EntityId> > FindItemLots(GameData game)
        {
            PARAM itemLots = game.Param("ItemLotParam");
            PARAM npcs     = game.Param("NpcParam");

            SortedDictionary <int, List <EntityId> > usedItemLots = new SortedDictionary <int, List <EntityId> >();

            // TODO: Merge in Sekiro map scraper, which is a fair bit more sophisticated.
            Dictionary <EntityId, EntityId>    objects      = new Dictionary <EntityId, EntityId>();
            Dictionary <int, List <EntityId> > usedNpcs     = new Dictionary <int, List <EntityId> >();
            Dictionary <int, List <EntityId> > usedEntities = new Dictionary <int, List <EntityId> >();

            foreach (KeyValuePair <string, MSB3> entry in game.Maps)
            {
                string location = game.Locations[entry.Key];
                foreach (MSB3.Part.Object part in entry.Value.Parts.Objects)
                {
                    EntityId id = new EntityId(location, part.Name, part.EventEntityID);
                    objects[id] = id;
                    if (part.EventEntityID > 0)
                    {
                        AddMulti(usedEntities, part.EventEntityID, id);
                    }
                }
                foreach (MSB3.Part.Enemy enemy in entry.Value.Parts.Enemies)
                {
                    EntityId id = new EntityId(location, enemy.Name, enemy.EventEntityID, enemy.NPCParamID, enemy.CharaInitID);
                    objects[id] = id;
                    if (enemy.NPCParamID > 0)
                    {
                        AddMulti(usedNpcs, enemy.NPCParamID, id);
                    }
                    if (enemy.EventEntityID > 0)
                    {
                        AddMulti(usedEntities, enemy.EventEntityID, id);
                    }
                }
            }
            foreach (KeyValuePair <string, MSB3> entry in game.Maps)
            {
                string location = game.Locations[entry.Key];
                foreach (MSB3.Event.Treasure treasure in entry.Value.Events.Treasures)
                {
                    if (treasure.PartName2 != null)
                    {
                        EntityId id = new EntityId(location, treasure.PartName2);
                        if (!objects.ContainsKey(id))
                        {
                            if (logUnused)
                            {
                                Console.WriteLine($"Missing entity for treasure {treasure.Name} with entity {treasure.PartName2} and lot {treasure.ItemLot1}");
                            }
                            continue;
                        }
                        AddMulti(usedItemLots, treasure.ItemLot1, objects[id]);
                    }
                }
            }
            foreach (PARAM.Row row in npcs.Rows)
            {
                int        npcID = (int)row.ID;
                PARAM.Cell cell  = row["ItemLotId1"];
                if (cell == null || (int)cell.Value == -1)
                {
                    continue;
                }
                int itemLot = (int)cell.Value;
                if (itemLots[itemLot] == null)
                {
                    if (logUnused)
                    {
                        Console.WriteLine($"Invalid NPC lot item for {npcID} with lot {itemLot}");
                    }
                    continue;
                }
                if (!usedNpcs.ContainsKey(npcID))
                {
                    if (logUnused)
                    {
                        Console.WriteLine($"Unused NPC: {npcID}");
                    }
                    continue;
                }
                AddMulti(usedItemLots, itemLot, usedNpcs[npcID]);
            }
            foreach (KeyValuePair <int, int> entry in entityItemLots)
            {
                int        entityId = entry.Key;
                List <int> itemLot  = new List <int> {
                    entry.Value
                };
                if (additionalEntityItemLots.ContainsKey(entityId))
                {
                    itemLot.AddRange(additionalEntityItemLots[entityId]);
                }
                if (!usedEntities.ContainsKey(entityId))
                {
                    Warn($"Missing NPC {entityId} with item lot {String.Join(", ", itemLot)}");
                    continue;
                }
                List <EntityId> id = usedEntities[entityId];
                foreach (int lot in itemLot)
                {
                    if (logUnused && (int)itemLots[lot]["getItemFlagId"].Value == -1 && id[0].GetModelID() != 2150)
                    {
                        Warn($"Eventless entity drop, not crystal lizard, for {String.Join(", ", id)} item lot {lot}");
                    }
                    AddMulti(usedItemLots, lot, id);
                }
            }
            foreach (int itemLot in Enumerable.Concat(talkLots, crowLots))
            {
                if ((int)itemLots[itemLot]["getItemFlagId"].Value == -1)
                {
                    Warn($"No event id attached to talk event {itemLot}");
                }
                AddMulti(usedItemLots, itemLot, new EntityId("", "from talk"));
            }
            if (logUnused)
            {
                int lastLot = 0;
                foreach (PARAM.Row lot in itemLots.Rows)
                {
                    int itemLot = (int)lot.ID;
                    if (itemLot == lastLot + 1)
                    {
                        // Don't require groups of item lots to be connected, only the base lot
                        lastLot = itemLot;
                        continue;
                    }
                    if (!usedItemLots.ContainsKey(itemLot))
                    {
                        Console.WriteLine($"Unconnected item lot {itemLot}: {game.LotName(itemLot)}");
                    }
                    lastLot = itemLot;
                }
            }
            return(usedItemLots);
        }
        public LocationData FindItems(GameData game)
        {
            SortedDictionary <int, List <EntityId> > usedItemLots = FindItemLots(game);

            PARAM shops     = game.Param("ShopLineupParam");
            PARAM itemLots  = game.Param("ItemLotParam");
            PARAM materials = game.Param("EquipMtrlSetParam");

            LocationData data = new LocationData();

            // Run through all item lots in the game in order, extract all the data.
            LocationKey prevLocation = null;

            foreach (KeyValuePair <int, List <EntityId> > entry in usedItemLots)
            {
                int itemLot = entry.Key;
                if (prevLocation != null)
                {
                    if (!crowLots.Contains(prevLocation.ID))
                    {
                        prevLocation.MaxSlots = itemLot - prevLocation.ID - 1;
                        if (prevLocation.MaxSlots < 1)
                        {
                            Warn($"Overlapping slots at {itemLot}");
                        }
                    }
                    prevLocation = null;
                }
                List <EntityId> entities = entry.Value;
                string          locs     = String.Join(", ", entities.Select(e => game.EntityName(e) + $" {e}"));
                if (itemLots[itemLot] == null)
                {
                    string text = game.LotName(itemLot);
                    // These are fine - no-ops to game
                    // Console.WriteLine($"MISSING connected item lot!! {itemLot}: {text} @ {locs}");
                    continue;
                }
                LocationKey baseLocation = null;
                while (itemLots[itemLot] != null)
                {
                    bool   isBase = itemLot == entry.Key;
                    string text   = game.LotName(itemLot);

                    PARAM.Row row         = itemLots[itemLot];
                    int       eventFlag   = (int)row["getItemFlagId"].Value;
                    int       totalPoints = 0;
                    for (int i = 1; i <= 8; i++)
                    {
                        totalPoints += (short)row[$"LotItemBasePoint0{i}"].Value;
                    }
                    for (int i = 1; i <= 8; i++)
                    {
                        int id = (int)row[$"ItemLotId{i}"].Value;
                        if (id != 0)
                        {
                            uint    type     = (uint)row[$"LotItemCategory0{i}"].Value;
                            int     points   = (short)row[$"LotItemBasePoint0{i}"].Value;
                            int     quantity = (byte)row[$"LotItemNum{i}"].Value;
                            ItemKey item     = new ItemKey(LocationData.LotTypes[type], id);
                            string  itemText = $"{itemLot}[{locs}]";
                            // Check out script about CC, btw
                            List <string> info = new List <string>();
                            if (quantity > 1)
                            {
                                info.Add($"{quantity}");
                            }
                            if (points != totalPoints)
                            {
                                info.Add($"{100.0 * points / totalPoints}%");
                            }
                            if (info.Count() > 0)
                            {
                                itemText += $" ({string.Join(",", info)})";
                            }
                            if (quantity <= 0 && logUnused)
                            {
                                Console.WriteLine($"There is 0! of {itemText}");
                            }
                            ItemScope scope;
                            if (eventFlag != -1)
                            {
                                if (equivalentEvents.ContainsKey(eventFlag))
                                {
                                    eventFlag = equivalentEvents[eventFlag];
                                }
                                scope = new ItemScope(ScopeType.EVENT, eventFlag);
                            }
                            else
                            {
                                // One time drops that directly award, that aren't covered by event flags. Mostly crystal lizards.
                                if (entities.Count() == 1 && entityItemLots.ContainsKey(entities[0].EventEntityID) && entityItemLots[entities[0].EventEntityID] == entry.Key)
                                {
                                    scope = new ItemScope(ScopeType.ENTITY, entities[0].EventEntityID);
                                }
                                // Non-respawning enemies with drops which can be missed. These are reused between different entities, so can drop multiple times.
                                else if (entities.All(e => nonRespawningEntities.Contains(e.EventEntityID)))
                                {
                                    scope = new ItemScope(ScopeType.ENTITY, entities.Select(e => e.EventEntityID).Min());
                                }
                                else
                                {
                                    int model = entities.Select(e => e.GetModelID()).Min();
                                    if (model == -1)
                                    {
                                        if (logUnused)
                                        {
                                            // Ideally this should not be randomized, but can't check here
                                            Console.WriteLine($"Infinite item {itemLot} with no event flags, entity flags, or models: {itemText}");
                                        }
                                        continue;
                                    }
                                    scope = new ItemScope(ScopeType.MODEL, model);
                                }
                            }
                            LocationKey location = new LocationKey(LocationType.LOT, itemLot, itemText, entities, quantity, baseLocation);
                            data.AddLocation(item, scope, location);
                            if (baseLocation == null)
                            {
                                baseLocation = location;
                            }
                        }
                    }
                    itemLot++;
                    if (crowLots.Contains(itemLot - 1))
                    {
                        break;
                    }
                }
                prevLocation = baseLocation;
            }
            foreach (PARAM.Row row in shops.Rows)
            {
                int    shopID   = (int)row.ID;
                string shopName = shopSplits[GetShopType(shopID)];
                if (shopName == null)
                {
                    continue;
                }
                int     qwc          = (int)row["qwcID"].Value;
                int     type         = (byte)row["equipType"].Value;
                int     id           = (int)row["EquipId"].Value;
                int     quantity     = (short)row["sellQuantity"].Value;
                int     eventFlag    = (int)row["EventFlag"].Value;
                int     material     = (int)row["mtrlId"].Value;
                string  quantityText = quantity == -1 ? "" : $" ({quantity})";
                string  qwcText      = qwc == -1 ? "" : $" {game.QwcName(qwc)}";
                ItemKey item         = new ItemKey((ItemType)type, id);
                string  text         = $"{shopName}{qwcText}{quantityText}";
                text = $"{shopID}[{text}]";
                LocationKey location = new LocationKey(LocationType.SHOP, shopID, text, new List <EntityId>(), quantity, null);
                ItemScope   scope;
                if (eventFlag != -1)
                {
                    if (equivalentEvents.ContainsKey(eventFlag))
                    {
                        eventFlag = equivalentEvents[eventFlag];
                    }
                    if (quantity <= 0)
                    {
                        Warn($"No quantity for event flag shop entry {text}");
                    }
                    ScopeType scopeType = ScopeType.EVENT;
                    if (restrictiveQwcs.Contains(qwc))
                    {
                        // In DS3, if item becomes unavailable at some point, that is because it returns in infinite form
                        scopeType = ScopeType.SHOP_INFINITE_EVENT;
                    }
                    scope = new ItemScope(scopeType, eventFlag);
                }
                else if (material != -1)
                {
                    int materialItem = (int)materials[material]["MaterialId01"].Value;
                    scope = new ItemScope(ScopeType.MATERIAL, materialItem);
                }
                else
                {
                    scope = new ItemScope(ScopeType.SHOP_INFINITE, -1);
                }
                data.AddLocation(item, scope, location);
            }
            // Merge infinite and finite shops. Mostly done via heuristic (when event and infinite both exist)
            ItemScope infiniteKey = new ItemScope(ScopeType.SHOP_INFINITE, -1);

            foreach (ItemLocations locations in data.Data.Values)
            {
                foreach (ItemLocation restrict in locations.Locations.Values.Where(loc => loc.Scope.Type == ScopeType.SHOP_INFINITE_EVENT).ToList())
                {
                    if (locations.Locations.ContainsKey(infiniteKey))
                    {
                        // Combine infinite shops into event
                        ItemLocation infinite = locations.Locations[infiniteKey];
                        restrict.Keys.AddRange(infinite.Keys);
                        locations.Locations.Remove(infiniteKey);
                    }
                    else
                    {
                        Warn($"No 1:1 match between event shops and infinite shops for {restrict}");
                        // No infinite shops, turn this into a regular event shop. (Doesn't happen in base DS3)
                        ItemLocation eventLoc = new ItemLocation(new ItemScope(ScopeType.EVENT, restrict.Scope.ID));
                        eventLoc.Keys.AddRange(restrict.Keys);
                        locations.Locations[eventLoc.Scope] = eventLoc;
                        locations.Locations.Remove(restrict.Scope);
                    }
                }
            }
            // Now calculate all location scopes - distinct item sources.
            // This is the main key for the annotations file, so scopes can be marked as missable or not, assigned logical areas, etc.
            // It is also used as the target for randomizing an item, because if several locations are equivalent, all should contain the same item.
            List <ScopeType> uniqueTypes = new List <ScopeType> {
                ScopeType.EVENT, ScopeType.ENTITY, ScopeType.MATERIAL
            };

            foreach (KeyValuePair <ItemKey, ItemLocations> entry in data.Data)
            {
                ItemKey item   = entry.Key;
                int     unique = 0;
                foreach (KeyValuePair <ItemScope, ItemLocation> entry2 in entry.Value.Locations)
                {
                    ItemScope    scope = entry2.Key;
                    ItemLocation loc   = entry2.Value;
                    int          id    = uniqueTypes.Contains(scope.Type) ? scope.ID : -1;
                    unique = unique == -1 ? -1 : (id == -1 ? -1 : unique + 1);
                    SortedSet <int> shopIds  = new SortedSet <int>(loc.Keys.Where(k => k.Type == LocationType.SHOP).Select(k => GetShopType(k.ID)));
                    SortedSet <int> shopQwcs = new SortedSet <int>(loc.Keys.Where(k => k.Type == LocationType.SHOP).Select(k => ((int)shops[k.ID]["qwcID"].Value, (int)shops[k.ID]["EventFlag"].Value))
                                                                   .Where(e => e.Item1 != -1 && (!restrictiveQwcs.Contains(e.Item1) || e.Item2 == -1))
                                                                   .Select(e => e.Item1));
                    SortedSet <int> allShop = new SortedSet <int>(shopIds.Union(shopQwcs));
                    if (shopIds.Count() + shopQwcs.Count() != allShop.Count())
                    {
                        Warn($"Overlapping qwc/shop ids for location {loc}");
                    }
                    SortedSet <int> modelBase     = scope.Type == ScopeType.MODEL ? new SortedSet <int>(loc.Keys.Select(k => k.BaseID)) : new SortedSet <int>();
                    bool            onlyShops     = loc.Keys.All(k => k.Type == LocationType.SHOP) && allShop.Count() > 0;
                    LocationScope   locationScope = new LocationScope(scope.Type, id, allShop, modelBase, onlyShops);
                    data.AddLocationScope(item, scope, locationScope);
                }
                entry.Value.Unique = unique > 0 && item.Type != ItemType.ARMOR;
            }

            if (logUnused)
            {
                foreach (KeyValuePair <ItemKey, string> entry in game.Names())
                {
                    ItemKey item = entry.Key;
                    if (item.Type == 0)
                    {
                        item = new ItemKey(item.Type, item.ID - (item.ID % 10000));
                    }
                    if (!data.Data.ContainsKey(item))
                    {
                        // Mostly pulls up old DS1 items and gestures.
                        Console.WriteLine($"Unused item {item.Type}-{entry.Key.ID}: {entry.Value}");
                    }
                }
            }
            return(data);
        }
            BOOL IMsoComponentManager.FPushMessageLoop(
                UIntPtr dwComponentID,
                msoloop uReason,
                void *pvLoopData)
            {
                // Hold onto old state to allow restore before we exit...
                msocstate currentLoopState = _currentState;
                BOOL      continueLoop     = BOOL.TRUE;

                if (!OleComponents.TryGetValue(dwComponentID, out ComponentHashtableEntry entry))
                {
                    return(BOOL.FALSE);
                }

                IMsoComponent prevActive = _activeComponent;

                try
                {
                    User32.MSG    msg = new User32.MSG();
                    IMsoComponent requestingComponent = entry.component;
                    _activeComponent = requestingComponent;

                    Debug.WriteLineIf(
                        CompModSwitches.MSOComponentManager.TraceInfo,
                        $"ComponentManager : Pushing message loop {uReason}");
                    Debug.Indent();

                    while (continueLoop.IsTrue())
                    {
                        // Determine the component to route the message to
                        IMsoComponent component = _trackingComponent ?? _activeComponent ?? requestingComponent;

                        bool useAnsi = false;
                        BOOL peeked  = User32.PeekMessageW(ref msg);

                        if (peeked.IsTrue())
                        {
                            useAnsi = msg.hwnd != IntPtr.Zero && User32.IsWindowUnicode(msg.hwnd).IsFalse();
                            if (useAnsi)
                            {
                                peeked = User32.PeekMessageA(ref msg);
                            }
                        }

                        if (peeked.IsTrue())
                        {
                            continueLoop = component.FContinueMessageLoop(uReason, pvLoopData, &msg);

                            // If the component wants us to process the message, do it.
                            if (continueLoop.IsTrue())
                            {
                                if (useAnsi)
                                {
                                    User32.GetMessageA(ref msg);
                                    Debug.Assert(User32.IsWindowUnicode(msg.hwnd).IsFalse());
                                }
                                else
                                {
                                    User32.GetMessageW(ref msg);
                                    Debug.Assert(msg.hwnd == IntPtr.Zero || User32.IsWindowUnicode(msg.hwnd).IsTrue());
                                }

                                if (msg.message == User32.WM.QUIT)
                                {
                                    Debug.WriteLineIf(
                                        CompModSwitches.MSOComponentManager.TraceInfo,
                                        "ComponentManager : Normal message loop termination");

                                    ThreadContext.FromCurrent().DisposeThreadWindows();

                                    if (uReason != msoloop.Main)
                                    {
                                        User32.PostQuitMessage(PARAM.ToInt(msg.wParam));
                                    }

                                    continueLoop = BOOL.FALSE;
                                    break;
                                }

                                // Now translate and dispatch the message.
                                //
                                // Reading through the rather sparse documentation,
                                // it seems we should only call FPreTranslateMessage
                                // on the active component.
                                if (component.FPreTranslateMessage(&msg).IsFalse())
                                {
                                    User32.TranslateMessage(ref msg);
                                    if (useAnsi)
                                    {
                                        User32.DispatchMessageA(ref msg);
                                    }
                                    else
                                    {
                                        User32.DispatchMessageW(ref msg);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // If this is a DoEvents loop, then get out. There's nothing left for us to do.
                            if (uReason == msoloop.DoEvents || uReason == msoloop.DoEventsModal)
                            {
                                break;
                            }

                            // Nothing is on the message queue. Perform idle processing and then do a WaitMessage.
                            bool continueIdle = false;

                            if (OleComponents is not null)
                            {
                                foreach (ComponentHashtableEntry idleEntry in OleComponents.Values)
                                {
                                    continueIdle |= idleEntry.component.FDoIdle(msoidlef.All).IsTrue();
                                }
                            }

                            // Give the component one more chance to terminate the message loop.
                            continueLoop = component.FContinueMessageLoop(uReason, pvLoopData, null);

                            if (continueLoop.IsTrue())
                            {
                                if (continueIdle)
                                {
                                    // If someone has asked for idle time, give it to them.  However,
                                    // don't cycle immediately; wait up to 100ms.  Why?  Because we don't
                                    // want someone to attach to idle, forget to detach, and then cause
                                    // CPU to end up in race condition.  For Windows Forms this generally isn't an issue because
                                    // our component always returns false from its idle request
                                    User32.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, User32.QS.ALLINPUT, User32.MWMO.INPUTAVAILABLE);
                                }
                                else
                                {
                                    // We should call GetMessage here, but we cannot because
                                    // the component manager requires that we notify the
                                    // active component before we pull the message off the
                                    // queue.  This is a bit of a problem, because WaitMessage
                                    // waits for a NEW message to appear on the queue.  If a
                                    // message appeared between processing and now WaitMessage
                                    // would wait for the next message.  We minimize this here
                                    // by calling PeekMessage.
                                    if (User32.PeekMessageW(ref msg, IntPtr.Zero, 0, 0, User32.PM.NOREMOVE).IsFalse())
                                    {
                                        User32.WaitMessage();
                                    }
                                }
                            }
                        }
                    }

                    Debug.Unindent();
                    Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, $"ComponentManager : message loop {uReason} complete.");
                }
                finally
                {
                    _currentState    = currentLoopState;
                    _activeComponent = prevActive;
                }

                return(continueLoop.IsFalse() ? BOOL.TRUE : BOOL.FALSE);
            }