private void _bAddNet_Click(object button, EventArgs e) { using var d = new System.Windows.Forms.OpenFileDialog { InitialDirectory = AFolders.ThisApp, Filter = "Dll|*.dll|All files|*.*", Multiselect = true }; if (d.ShowDialog(this) != DialogResult.OK) { return; } var a = d.FileNames; foreach (var v in a) { if (MetaReferences.IsDotnetAssembly(v)) { continue; } ADialog.ShowError("Not a .NET assembly.", v, owner: this); return; } //remove path and ext if need var thisApp = AFolders.ThisAppBS; if (a[0].Starts(thisApp, true)) { for (int i = 0; i < a.Length; i++) { a[i] = a[i].Substring(thisApp.Length); } } _meta.r.AddRange(a); _Added(button, _meta.r); }
//protected override void OnGotFocus(EventArgs e) { _c.Focus(); } /// <summary> /// Loads existing or new workspace. /// If fails, shows a task dialog with several choices - retry, load another, create new, cancel. If then fails, ends process. /// Sets Model and Text properties of the main form. Updates recent files. /// By default runs startup script. /// </summary> /// <param name="wsDir"> /// Workspace's directory. The directory should contain file "files.xml" and subdirectory "files". /// If null, loads the last used workspace (its path is in settings). /// If the setting does not exist, uses AFolders.ThisAppDocuments + @"Main". /// If the file does not exist, copies from AFolders.ThisApp + @"Default\Workspace". /// </param> public FilesModel ZLoadWorkspace(string wsDir = null) { wsDir ??= Program.Settings.workspace; if(wsDir.NE()) wsDir = AFolders.ThisAppDocuments + "Main"; var xmlFile = wsDir + @"\files.xml"; var oldModel = _model; FilesModel m = null; _isNewWorkspace = false; g1: try { //SHOULDDO: if editor runs as admin, the workspace directory should be write-protected from non-admin processes. if(_isNewWorkspace = !AFile.ExistsAsFile(xmlFile)) { AFile.Copy(AFolders.ThisAppBS + @"Default\Workspace", wsDir); } _model?.UnloadingWorkspace(); //saves all, closes documents, sets current file = null m = new FilesModel(_c, xmlFile); _c.Model = m; } catch(Exception ex) { m?.Dispose(); m = null; //AOutput.Write($"Failed to load '{wsDir}'. {ex.Message}"); switch(ADialog.ShowError("Failed to load workspace", wsDir, "1 Retry|2 Load another|3 Create new|0 Cancel", owner: this, expandedText: ex.ToString())) { case 1: goto g1; case 2: m = ZLoadAnotherWorkspace(); break; case 3: m = ZLoadNewWorkspace(); break; } if(m != null) return m; if(_model != null) return _model; Environment.Exit(1); } oldModel?.Dispose(); Program.Model = _model = m; //CONSIDER: unexpand path if(wsDir != Program.Settings.workspace) { if(Program.Settings.workspace != null) { var ar = Program.Settings.recentWS ?? Array.Empty<string>(); int i = Array.IndexOf(ar, wsDir); if(i >= 0) ar = ar.RemoveAt(i); Program.Settings.recentWS = ar.InsertAt(0, Program.Settings.workspace); } Program.Settings.workspace = wsDir; } Program.MainForm.ZSetTitle(); if(Program.Loaded >= EProgramState.LoadedWorkspace) { ZOpenDocuments(); ZModel.RunStartupScripts(); } return _model; }
/// <summary> /// Shows "Open" dialog to select an existing workspace. /// On OK loads the selected workspace and returns FilesModel. On Cancel return null. /// </summary> public FilesModel ZLoadAnotherWorkspace() { var d = new OpenFileDialog { Title = "Open workspace", Filter = "files.xml|files.xml" }; if(d.ShowDialog(this) != DialogResult.OK) return null; var filesXml = d.FileName; if(!APath.GetFileName(filesXml).Eqi("files.xml")) { ADialog.ShowError("Must be files.xml"); return null; } return ZLoadWorkspace(APath.GetDirectoryPath(filesXml)); }
/// <summary> /// Used only by the Save class. /// </summary> bool _SaveWorkspaceNow() { try { //AOutput.Write("saving"); Root.Save(WorkspaceFile); return(true); } catch (Exception ex) { //XElement.Save exceptions are undocumented ADialog.ShowError("Failed to save", WorkspaceFile, expandedText: ex.Message); return(false); } }
private void _ButtonOK_Click(object sender, EventArgs e) { var ok = true; var path = textPath.Text; if (!APath.IsFullPath(path)) { ok = false; } else if (AFile.ExistsAsAny(path)) { ADialog.ShowError("Already exists", path, owner: this); ok = false; } this.DialogResult = ok ? DialogResult.OK : DialogResult.None; }
async void _ConvertTypeLibrary(object tlDef, object button) { string comDll = null; switch (tlDef) { case string path: comDll = path; break; case _RegTypelib r: //can be several locales var aloc = new List <string>(); //registry keys like "0" or "409" var aloc2 = new List <string>(); //locale names for display in the list dialog using (var verKey = Registry.ClassesRoot.OpenSubKey($@"TypeLib\{r.guid}\{r.version}")) { foreach (var s1 in verKey.GetSubKeyNames()) { int lcid = s1.ToInt(0, out int iEnd, STIFlags.IsHexWithout0x); if (iEnd != s1.Length) { continue; //"FLAGS" etc; must be hex number without 0x } aloc.Add(s1); var s2 = "Neutral"; if (lcid > 0) { try { s2 = new CultureInfo(lcid).DisplayName; } catch { s2 = s1; } } aloc2.Add(s2); } } string locale; if (aloc.Count == 1) { locale = aloc[0]; } else { int i = ADialog.ShowList(aloc2, "Locale", owner: this); if (i == 0) { return; } locale = aloc[i - 1]; } comDll = r.GetPath(locale); if (comDll == null || !AFile.ExistsAsFile(comDll)) { ADialog.ShowError(comDll == null ? "Failed to get file path." : "File does not exist.", owner: this); return; } break; } await Task.Run(() => { this.Enabled = false; AOutput.Write($"Converting COM type library to .NET assembly."); try { if (_convertedDir == null) { _convertedDir = AFolders.Workspace + @".interop\"; AFile.CreateDirectory(_convertedDir); } List <string> converted = new List <string>(); Action <string> callback = s => { AOutput.Write(s); if (s.Starts("Converted: ")) { s.RegexMatch(@"""(.+?)"".$", 1, out s); converted.Add(s); } }; int rr = AExec.RunConsole(callback, AFolders.ThisAppBS + "Au.Net45.exe", $"/typelib \"{_convertedDir}|{comDll}\"", encoding: Encoding.UTF8); if (rr == 0) { foreach (var v in converted) { if (!_meta.com.Contains(v)) { _meta.com.Add(v); } } AOutput.Write(@"<>Converted and saved in <link>%AFolders.Workspace%\.interop<>."); _Added(button, _meta.com); } } catch (Exception ex) { ADialog.ShowError("Failed to convert type library", ex.ToStringWithoutStack(), owner: this); } this.Enabled = true; }); }
/// <summary> /// Starts or stops capturing. /// Does nothing if already in that state. /// </summary> public void StartStop(bool start) { if (start == Capturing) { return; } var wForm = (AWnd)_form; if (start) { //let other forms stop capturing wForm.Prop.Set(c_propName, 1); AWnd.Find(null, "WindowsForms*", also: o => { if (o != wForm && o.Prop[c_propName] == 1) { o.Send(c_stopMessage); } return(false); }); if (!Api.RegisterHotKey(wForm, 1, 0, KKey.F3)) { ADialog.ShowError("Failed to register hotkey F3", owner: _form); return; } Capturing = true; //set timer that shows AO rect if (_timer == null) { _osr = TUtil.CreateOsdRect(); _timer = new ATimer(t => { //Don't capture too frequently. // Eg if the callback is very slow. Or if multiple timer messages are received without time interval (possible in some conditions). long t1 = ATime.PerfMilliseconds, t2 = t1 - _prevTime; _prevTime = t1; if (t2 < 100) { return; } //show rect of UI object from mouse AWnd w = AWnd.FromMouse(WXYFlags.NeedWindow); RECT?r = default; if (!(w.Is0 || w == wForm || w.OwnerWindow == wForm)) { r = _cbGetRect(); } if (r.HasValue) { var rr = r.GetValueOrDefault(); rr.Inflate(2, 2); //2 pixels inside, 2 outside _osr.Rect = rr; _osr.Show(); } else { _osr.Visible = false; } }); } _timer.Every(250); } else { Capturing = false; Api.UnregisterHotKey(wForm, 1); wForm.Prop.Remove(c_propName); _timer.Stop(); _osr.Hide(); } }
/// <summary> /// Opens XML file and creates toolbars/menus/submenus from XML tags. /// </summary> /// <param name="xmlFile">XML file containing menus/toolbars without user customizations.</param> /// <param name="xmlFileCustom">XML file containing user customizations. It will be created or updated when saving customizations.</param> /// <param name="tsRenderer"></param> public void BuildAll(string xmlFile, string xmlFileCustom, ToolStripRenderer tsRenderer = null) { Debug.Assert(_xStrips == null); if (_xStrips != null) { throw new InvalidOperationException(); } _xmlFileDefault = xmlFile; _xmlFileCustom = xmlFileCustom; try { _xStrips = AExtXml.LoadElem(xmlFile); } catch (Exception ex) { ADialog.ShowError("Failed to load file", ex.ToString()); throw; } XElement xCustom = null; if (AFile.ExistsAsFile(_xmlFileCustom)) { try { xCustom = AExtXml.LoadElem(_xmlFileCustom); } catch (Exception e) { AOutput.Write("Failed to load file", _xmlFileCustom, e.Message); } } Size imageScalingSize = Au.Util.ADpi.SmallIconSize_; //if high DPI, auto scale images //create top-level toolstrips (menu bar and toolbars), and call _AddChildItems to add items and create drop-down menus and submenus _inBuildAll = true; bool isMenu = true; foreach (var xe in _xStrips.Elements().ToArray()) //info: ToArray() because _MergeCustom replaces XML elements of custom toolbars { string name = xe.Name.LocalName; var x = xe; if (xCustom != null) { _MergeCustom(xCustom, ref x, name, isMenu); } ToolStrip t; if (isMenu) { t = MenuBar = new Util.AMenuStrip(); } else { var cts = new Util.AToolStrip(); Toolbars.Add(name, cts); t = cts; switch (name) { case "Custom1": _tsCustom1 = cts; break; case "Custom2": _tsCustom2 = cts; break; } } t.SuspendLayout(); t.Tag = x; t.Text = t.Name = name; //t.AllowItemReorder = true; //don't use, it's has bugs etc, we know better how to do it if (tsRenderer != null) { t.Renderer = tsRenderer; } if (isMenu) { t.Padding = new Padding(); //remove menu bar paddings } else { } if (imageScalingSize.Height != 16) { t.ImageScalingSize = imageScalingSize; //info: all submenus will inherit it from menubar } _AddChildItems(x, t, isMenu); t.ResumeLayout(false); isMenu = false; } _inBuildAll = false; }
//Loads and parses XML. Creates the _aX lists, _firstSplit and the tree structure. void _LoadXmlAndCreateLayout(string xmlFileDefault, string xmlFileCustomized) { //We have 1 or 2 XML files containing panel/toolbar layout. //xmlFileDefault contains default XML. It eg can be in AFolders.ThisApp. //xmlFileCustomized contains previously saved XML (user-modified layout). //At first try to load xmlFileCustomized. If it does not exist or is invalid, load xmlFileDefault; or get missing data from xmlFileDefault, if possible. //Also loads xmlFileDefault when xmlFileCustomized XML does not match panels of new app version and cannot resolve it (eg some panels removed). bool usesDefaultXML = false; string xmlFile = xmlFileCustomized, xmlVersion = null, outInfo = null; for (int i = 0; i < 2; i++) { if (i == 0) { if (!AFile.ExistsAsFile(xmlFile)) { continue; } } else { usesDefaultXML = true; xmlFile = xmlFileDefault; } bool fileLoaded = false; try { var x = AExtXml.LoadElem(xmlFile); fileLoaded = true; if (!usesDefaultXML) { xmlVersion = x.Attr("version"); } x = x.Element("split"); //THIS DOES THE MAIN JOB _firstSplit = new _Split(this, null, x); if (_aPanel.Count < _initControls.Count) //more panels added in this app version { if (usesDefaultXML) { throw new Exception("debug1"); } _GetPanelXmlFromDefaultFile(xmlFileDefault); } break; //speed: xml.Load takes 170 microseconds. //tested: XML can be added to Application Settings, but var xml=Properties.Settings.Default.PanelsXML takes 61 MILLIseconds. } catch (Exception e) { var sErr = $"Failed to load file '{xmlFile}'.\r\n\t{e.ToStringWithoutStack()}"; if (usesDefaultXML) { _xmlFile = null; ADialog.ShowError("Cannot load panel/toolbar layout.", $"{sErr}\r\n\r\nReinstall the application."); Environment.Exit(1); } else { //probably in this version there are less panels, most likely when downgraded. Or the file is corrupt. if (fileLoaded && xmlVersion != _asmVersion) { outInfo = "Info: this application version resets the panel/toolbar layout, sorry."; } else { AWarning.Write(sErr, -1); } } _aSplit.Clear(); _aTab.Clear(); _aPanel.Clear(); } } //if(usesDefaultXML || xmlVersion == _asmVersion) return; if (outInfo != null) { AOutput.Write(outInfo); } }
/// <summary> /// Processes command line of this program. /// Returns true if this instance must exit: 1. If finds previous program instance; then sends the command line to it if need. 2. If incorrect command line. /// </summary> public static bool OnProgramStarted(string[] a) { string s = null; int cmd = 0; bool activateWnd = true; if (a.Length > 0) { //AOutput.Write(a); for (int i = 0; i < a.Length; i++) { if (a[i].Starts('-')) { a[i] = a[i].ReplaceAt(0, 1, "/"); } if (a[i].Starts('/')) { a[i] = a[i].Lower(); } } s = a[0]; if (s.Starts('/')) { for (int i = 0; i < a.Length; i++) { s = a[i]; switch (s) { case "/test": if (++i < a.Length) { TestArg = a[i]; } break; case "/v": StartVisible = true; break; default: ADialog.ShowError("Unknown command line parameter", s); return(true); } //rejected: /h start hidden. Not useful. } } else //one or more files { if (a.Length == 1 && FilesModel.IsWorkspaceDirectory(s)) { switch (cmd = ADialog.Show("Workspace", s, "1 Open|2 Import|0 Cancel", footerText: FilesModel.GetSecurityInfo("v|"))) { case 1: WorkspaceDirectory = s; break; case 2: _importWorkspace = s; break; } } else { cmd = 3; _importFiles = a; } } } //single instance s_mutex = new Mutex(true, "Au.Mutex.1", out bool createdNew); if (createdNew) { return(false); } var w = AWnd.FindFast(null, "Au.Editor.Msg", true); if (!w.Is0) { if (activateWnd) { AWnd wMain = (AWnd)w.Send(Api.WM_USER); if (!wMain.Is0) { try { wMain.Activate(); } catch (Exception ex) { ADebug.Print(ex); } } } switch (cmd) { case 3: //import files s = string.Join("\0", a); break; } if (cmd != 0) { AWnd.More.CopyDataStruct.SendString(w, cmd, s); } } return(true); }