/// <summary> /// Compares this string with a string that possibly contains wildcard characters. /// Returns true if the strings match. /// </summary> /// <param name="t">This string. If null, returns false. If "", returns true if pattern is "" or "*".</param> /// <param name="pattern">String that possibly contains wildcard characters. Cannot be null. If "", returns true if this string is "". If "*", always returns true except when this string is null.</param> /// <param name="ignoreCase">Case-insensitive.</param> /// <remarks> /// Wildcard characters: /// /// Character | Will match | Examples /// | - | - | - | /// | * | Zero or more of any characters. | <c>"start*"</c>, <c>"*end"</c>, <c>"*middle*"</c> /// | ? | Any single character. | <c>"date ????-??-??"</c> /// /// There are no escape sequences for * and ? characters. /// /// Uses ordinal comparison, ie does not depend on current culture. /// /// Much faster than regular expression. /// /// See also: [](xref:wildcard_expression). /// </remarks> /// <example> /// <code><![CDATA[ /// string s = @"C:\abc\mno.xyz"; /// if(s.Like(@"C:\abc\mno.xyz")) AOutput.Write("matches whole text (no wildcard characters)"); /// if(s.Like(@"C:\abc\*")) AOutput.Write("starts with"); /// if(s.Like(@"*.xyz")) AOutput.Write("ends with"); /// if(s.Like(@"*mno*")) AOutput.Write("contains"); /// if(s.Like(@"C:\*.xyz")) AOutput.Write("starts and ends with"); /// if(s.Like(@"?:*")) AOutput.Write("any character, : and possibly more text"); /// ]]></code> /// </example> /// <seealso cref="AWildex"/> #if false //somehow speed depends on dll version. With some versions same as C# code, with some slower. Also depends on string. With shortest strings 50% slower. public static bool Like(this string t, string pattern, bool ignoreCase = false) { if (t == null) { return(false); fixed(char *pt = t, pw = pattern) return(Cpp.Cpp_StringLike(pt, t.Length, pw, pattern.Length, ignoreCase)); }
//#region IReflect //FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) => null; //FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) => null; //MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) => null; //MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) => null; //MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) => null; //MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) => null; //MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) => null; //PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) => null; //PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) => null; //PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) => null; //object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters) => null; //Type IReflect.UnderlyingSystemType => null; //#endregion /// <summary> /// Call in hook wndproc on WM_GETOBJECT like this: <c>handled = true; return (_acc ??= new _Accessible(this)).WmGetobject(wParam, lParam);</c>. /// If lParam is EObjid.CLIENT, calls API LresultFromObject(this), else calls API DefWindowProc. /// </summary> public nint WmGetobject(nint wParam, nint lParam) { var oid = (EObjid)lParam; //print.it(oid); if (oid != EObjid.CLIENT) { return(Api.DefWindowProc(_w, Api.WM_GETOBJECT, wParam, lParam)); } return(Cpp.Cpp_AccWorkaround(this, wParam, ref _accWorkaround)); //cannot use this because of .NET bug: then calls our IAccessible implementation methods in other thread. //var accIP = Marshal.GetIUnknownForObject(this); ////var accIP=Marshal.GetIDispatchForObject(this); //var r = Api.LresultFromObject(typeof(IAccessible).GUID, wParam, accIP); ////Marshal.AddRef(accIP); print.it(Marshal.Release(accIP)); //Marshal.Release(accIP); //return r; }
public bool InsideString(bool charJustAdded, int position) //need to refactor this out too. { Cpp style = (Cpp)GetStyleAt(position - (charJustAdded ? 2 : 1)); if (style == Cpp.String) { return(true); } int lineNumber = LineFromPosition(position); int lineStart = PositionFromLine(lineNumber); string curLine = GetLine(lineNumber); if (curLine.Length > 0) { int length = position - lineStart; if (length >= curLine.Length) { length = curLine.Length - 1; } curLine = curLine.Substring(0, length); } if (curLine.IndexOf('"') >= 0) { int curIndex = 0; int numSpeechMarks = 0; while ((curIndex = curLine.IndexOf('"', curIndex)) >= 0) { numSpeechMarks++; curIndex++; } if (numSpeechMarks % 2 == 1) { // in a string literal return(true); } } return(false); }
wnd _wTargetControl; //control or window from mouse int _InvokeDropTarget(wnd w, DDEvent ev, int effect, int keyState, POINT pt) { nint prop = w.Prop["OleDropTargetInterface"]; if (prop == 0 && w != _wWindow) //if w is of a HwndHost that does not register drop target, use that of the main window { w = _wWindow; prop = w.Prop["OleDropTargetInterface"]; } if (prop == 0) { return(0); } var data = ev == DDEvent.Enter || ev == DDEvent.Drop ? _data : null; int hr = Cpp.Cpp_CallIDroptarget(prop, (int)ev, data, keyState, pt, ref effect); if (hr != 0) { effect = 0; } return(effect); //working with COM in C# often is difficult. Cannot call IDropTarget methods. }
/// <summary> /// Runs/opens a program, document, directory (folder), URL, new email, Control Panel item etc. /// The returned <see cref="RResult"/> variable contains some process info - process id etc. /// </summary> /// <param name="file"> /// Examples: /// - <c>@"C:\file.txt"</c> /// - <c>folders.Documents</c> /// - <c>folders.System + "notepad.exe"</c> /// - <c>@"%folders.System%\notepad.exe"</c> /// - <c>@"%TMP%\file.txt"</c> /// - <c>"notepad.exe"</c> /// - <c>@"..\folder\x.exe"</c> /// - <c>"http://a.b.c/d"</c> /// - <c>"file:///path"</c> /// - <c>"mailto:[email protected]"</c> /// - <c>":: ITEMIDLIST"</c> /// - <c>@"shell:::{CLSID}"</c> /// - <c>@"shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"</c>. /// More info in Remarks. /// </param> /// <param name="args"> /// Command line arguments. /// This function expands environment variables if starts with <c>"%"</c> or <c>"\"%"</c>. /// </param> /// <param name="flags"></param> /// <param name="dirEtc"> /// Allows to specify more parameters: current directory, verb, etc. /// If string, it sets initial current directory for the new process. If "", gets it from <i>file</i>. More info: <see cref="ROptions.CurrentDirectory"/>. /// </param> /// <exception cref="ArgumentException">Used both <b>ROptions.Verb</b> and <b>RFlags.Admin</b> and this process isn't admin.</exception> /// <exception cref="AuException">Failed. For example, the file does not exist.</exception> /// <remarks> /// It works like when you double-click a file icon. It may start new process or not. For example it may just activate window if the program is already running. /// Uses API <msdn>ShellExecuteEx</msdn>. /// Similar to <see cref="Process.Start(string, string)"/>. /// /// The <i>file</i> parameter can be: /// - Full path of a file or directory. Examples: <c>@"C:\file.txt"</c>, <c>folders.Documents</c>, <c>folders.System + "notepad.exe"</c>, <c>@"%folders.System%\notepad.exe"</c>. /// - Filename of a file or directory, like <c>"notepad.exe"</c>. The function calls <see cref="filesystem.searchPath"/>. /// - Path relative to <see cref="folders.ThisApp"/>. Examples: <c>"x.exe"</c>, <c>@"subfolder\x.exe"</c>, <c>@".\subfolder\x.exe"</c>, <c>@"..\another folder\x.exe"</c>. /// - URL. Examples: <c>"https://www.example.com"</c>, <c>"file:///path"</c>. /// - Email, like <c>"mailto:[email protected]"</c>. Subject, body etc also can be specified, and Google knows how. /// - Shell object's ITEMIDLIST like <c>":: ITEMIDLIST"</c>. See <see cref="Pidl.ToHexString"/>, <see cref="folders.shell"/>. Can be used to open virtual folders and items like Control Panel. /// - Shell object's parsing name, like <c>@"shell:::{CLSID}"</c> or <c>@"::{CLSID}"</c>. See <see cref="Pidl.ToShellString"/>. Can be used to open virtual folders and items like Control Panel. /// - To run a Windows Store App, use <c>@"shell:AppsFolder\WinStoreAppId"</c> format. Examples: <c>@"shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"</c>, <c>@"shell:AppsFolder\windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel"</c>. To discover the string use hotkey Ctrl+Shift+Q or function <see cref="WndUtil.GetWindowsStoreAppId"/> or Google. /// /// Supports environment variables, like <c>@"%TMP%\file.txt"</c>. See <see cref="pathname.expand"/>. /// </remarks> /// <seealso cref="wnd.find"/> /// <seealso cref="wnd.findOrRun"/> /// <seealso cref="wnd.runAndFind"/> /// <example> /// Run Notepad and wait for an active Notepad window. /// <code><![CDATA[ /// run.it("notepad.exe"); /// 1.s(); /// wnd w = wnd.wait(10, true, "*- Notepad", "Notepad"); /// ]]></code> /// Run Notepad or activate a Notepad window. /// <code><![CDATA[ /// wnd w = wnd.findOrRun("*- Notepad", run: () => run.it("notepad.exe")); /// ]]></code> /// Run File Explorer and wait for new folder window. Ignores matching windows that already existed. /// <code><![CDATA[ /// var w = wnd.runAndFind( /// () => run.it(@"explorer.exe"), /// 10, cn: "CabinetWClass"); /// ]]></code> /// </example> public static RResult it(string file, string args = null, RFlags flags = 0, ROptions dirEtc = null) { Api.SHELLEXECUTEINFO x = default; x.cbSize = Api.SizeOf(x); x.fMask = Api.SEE_MASK_NOZONECHECKS | Api.SEE_MASK_NOASYNC | Api.SEE_MASK_CONNECTNETDRV | Api.SEE_MASK_UNICODE; x.nShow = Api.SW_SHOWNORMAL; bool curDirFromFile = false; var more = dirEtc; if (more != null) { x.lpVerb = more.Verb; if (x.lpVerb != null) { x.fMask |= Api.SEE_MASK_INVOKEIDLIST; //makes slower. But verbs are rarely used. } if (more.CurrentDirectory is string cd) { if (cd.Length == 0) { curDirFromFile = true; } else { cd = pathname.expand(cd); } x.lpDirectory = cd; } if (!more.OwnerWindow.IsEmpty) { x.hwnd = more.OwnerWindow.Hwnd.Window; } switch (more.WindowState) { case ProcessWindowStyle.Hidden: x.nShow = Api.SW_HIDE; break; case ProcessWindowStyle.Minimized: x.nShow = Api.SW_SHOWMINIMIZED; break; case ProcessWindowStyle.Maximized: x.nShow = Api.SW_SHOWMAXIMIZED; break; } x.fMask &= ~more.FlagsRemove; x.fMask |= more.FlagsAdd; } if (flags.Has(RFlags.Admin)) { if (x.lpVerb == null || x.lpVerb.Eqi("runas")) { x.lpVerb = "runas"; } else if (!uacInfo.isAdmin) { throw new ArgumentException("Cannot use Verb with flag Admin, unless this process is admin"); } } file = _NormalizeFile(false, file, out bool isFullPath, out bool isShellPath); Pidl pidl = null; if (isShellPath) //":: ITEMIDLIST" or "::{CLSID}..." (we convert it too because the API does not support many) { pidl = Pidl.FromString(file); //does not throw if (pidl != null) { x.lpIDList = pidl.UnsafePtr; x.fMask |= Api.SEE_MASK_INVOKEIDLIST; } else { x.lpFile = file; } } else { x.lpFile = file; if (curDirFromFile && isFullPath) { x.lpDirectory = pathname.getDirectory(file); } } x.lpDirectory ??= Directory.GetCurrentDirectory(); if (!args.NE()) { x.lpParameters = pathname.expand(args); } if (0 == (flags & RFlags.ShowErrorUI)) { x.fMask |= Api.SEE_MASK_FLAG_NO_UI; } if (0 == (flags & RFlags.WaitForExit)) { x.fMask |= Api.SEE_MASK_NO_CONSOLE; } if (0 != (flags & RFlags.MostUsed)) { x.fMask |= Api.SEE_MASK_FLAG_LOG_USAGE; } x.fMask |= Api.SEE_MASK_NOCLOSEPROCESS; WndUtil.EnableActivate(-1); bool waitForExit = 0 != (flags & RFlags.WaitForExit); bool needHandle = flags.Has(RFlags.NeedProcessHandle); bool ok = false; int pid = 0, errorCode = 0; bool asUser = !flags.HasAny(RFlags.Admin | RFlags.InheritAdmin) && uacInfo.isAdmin; //info: new process does not inherit uiAccess if (asUser) { ok = Cpp.Cpp_ShellExec(x, out pid, out int injectError, out int execError); if (!ok) { if (injectError != 0) { print.warning("Failed to run as non-admin."); asUser = false; } else { errorCode = execError; } } } if (!asUser) { ok = Api.ShellExecuteEx(ref x); if (!ok) { errorCode = lastError.code; } } pidl?.Dispose(); if (!ok) { throw new AuException(errorCode, $"*run '{file}'"); } var R = new RResult(); WaitHandle_ ph = null; if (needHandle || waitForExit) { if (pid != 0) { x.hProcess = Handle_.OpenProcess(pid, Api.PROCESS_ALL_ACCESS); } if (!x.hProcess.Is0) { ph = new WaitHandle_(x.hProcess, true); } } if (!waitForExit) { if (pid != 0) { R.ProcessId = pid; } else if (!x.hProcess.Is0) { R.ProcessId = process.processIdFromHandle(x.hProcess); } } try { Api.AllowSetForegroundWindow(); if (x.lpVerb != null && Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) { Thread.CurrentThread.Join(50); //need min 5-10 for file Properties. And not Sleep. } if (ph != null) { if (waitForExit) { ph.WaitOne(); if (Api.GetExitCodeProcess(x.hProcess, out var exitCode)) { R.ProcessExitCode = exitCode; } } if (needHandle) { R.ProcessHandle = ph; } } } finally { if (R.ProcessHandle == null) { if (ph != null) { ph.Dispose(); } else { x.hProcess.Dispose(); } } } return(R); //tested: works well in MTA thread. //rejected: in QM2, run also has a 'window' parameter. However it just makes limited, unclear etc, and therefore rarely used. Instead use wnd.findOrRun or Find/Run/Wait like in the examples. //rejected: in QM2, run also has 'autodelay'. Better don't add such hidden things. Let the script decide what to do. }
private void Style(int linenum, int end) { int line_length = SendMessageDirect(Constants.SCI_LINELENGTH, linenum); int start_pos = SendMessageDirect(Constants.SCI_POSITIONFROMLINE, linenum); int laststyle = start_pos; Cpp stylingMode; if (start_pos > 0) { stylingMode = (Cpp)GetStyleAt(start_pos - 1); } else { stylingMode = Cpp.Default; } bool onNewLine = true; bool onScriptLine = false; int i; SendMessageDirect(Constants.SCI_STARTSTYLING, start_pos, 0x1f); for (i = start_pos; i <= end; i++) { char c = (char)GetCharAt(i); if (!Char.IsLetterOrDigit(c) && (stylingMode != Cpp.Comment || stylingMode != Cpp.CommentLine || stylingMode != Cpp.String)) { string lastword = previousWordFrom(i); if (lastword.Length != 0) { Cpp newMode = stylingMode; if (onScriptLine && Keywords.Contains(lastword.Trim())) { newMode = Cpp.Word; } if (!onScriptLine && stylingMode == Cpp.Word2) // before colon { if (lastword.Trim() == "return" || lastword.Trim() == "stop") { newMode = Cpp.Word; } } if (newMode != stylingMode) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle - lastword.Length, (int)stylingMode); SendMessageDirect(Constants.SCI_SETSTYLING, lastword.Length, (int)newMode); laststyle = i; } } } if (c == '\n') { onNewLine = true; onScriptLine = false; if (stylingMode != Cpp.Comment && stylingMode != Cpp.String) { if (laststyle < i) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); laststyle = i; } stylingMode = Cpp.Default; } continue; } if (onNewLine) { if (c == ' ') { onScriptLine = true; onNewLine = false; continue; } } if (onScriptLine) { if (isOperator(c)) { if (stylingMode != Cpp.String && stylingMode != Cpp.Comment && stylingMode != Cpp.CommentLine) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); SendMessageDirect(Constants.SCI_SETSTYLING, 1, (int)Cpp.Operator); stylingMode = Cpp.Default; laststyle = i + 1; } } else if (isNumeric(c)) { if (stylingMode != Cpp.String && stylingMode != Cpp.Comment && stylingMode != Cpp.CommentLine) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); SendMessageDirect(Constants.SCI_SETSTYLING, 1, (int)Cpp.Number); stylingMode = Cpp.Default; laststyle = i + 1; } } else if (c == '"') { if (stylingMode == Cpp.String) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle + 1, (int)stylingMode); laststyle = i + 1; stylingMode = Cpp.Default; } else { stylingMode = Cpp.String; } } } else { if (onNewLine && stylingMode != Cpp.Comment) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); stylingMode = Cpp.Word2; laststyle = i; } if (c == ':' && stylingMode != Cpp.Comment && stylingMode != Cpp.CommentLine) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle + 1, (int)stylingMode); laststyle = i + 1; stylingMode = Cpp.Number; } if (c == '@' && stylingMode == Cpp.Word2) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); stylingMode = Cpp.Number; laststyle = i; } } if (c == '/') { if (stylingMode == Cpp.Comment && GetCharAt(i - 1) == '*') { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle + 1, (int)stylingMode); stylingMode = Cpp.Default; laststyle = i + 1; } else if (GetCharAt(i + 1) == '*' && onScriptLine) { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); stylingMode = Cpp.Comment; laststyle = i; } else if (GetCharAt(i + 1) == '/') { SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); stylingMode = Cpp.CommentLine; laststyle = i; } } onNewLine = false; } SendMessageDirect(Constants.SCI_SETSTYLING, i - laststyle, (int)stylingMode); }