03-05-2024, 08:25 AM
Thanks MBaas for sharing your code.
I also love and recommend xyPlorer as filemanager and created a little helper class prXyPlorer to interact with it from LA.
There are two possible ways of interaction between LA and xyPlorer:
Sample calls of helper class could be like following to get back the actual path of first active tab in xyPlorer:
Any suggestions or extensions of that prXyPlorer-helperclass are welcome.
[/code]
[/code]
I also love and recommend xyPlorer as filemanager and created a little helper class prXyPlorer to interact with it from LA.
There are two possible ways of interaction between LA and xyPlorer:
- Messages from LA to xyPlorer like your code-snippet does
- Using commandline option /feed= of xyPlorer which my class also implements
Sample calls of helper class could be like following to get back the actual path of first active tab in xyPlorer:
- prXyplorer.SendToXyPlorer("tab('get', 'path', 1)");
- prXyplorer.FeedToXyPlorer("tab('get', 'path', 1)");
Any suggestions or extensions of that prXyPlorer-helperclass are welcome.
[code]// class "prXyPlorer.cs"
/*/
role classLibrary;
outputPath %folders.Workspace%\dll;
/*/
using System.Text;
using Au;
using Au.More;
public class prXyplorer {
#region Fields
/// <summary>
/// Startup directory of xyPlorer (working directory with scripts).
/// </summary>
public static string xyDir = @"C:\Users\Siegfried\AppData\Roaming\XYplorer";
/// <summary>
/// Full path to xyPlorer exe.
/// </summary>
public static string xyExe = @"C:\Program Files (x86)\XYplorer\XYplorer.exe";
private static wnd wndReceiver = default;
#endregion Fields
#region Methods
/// <summary>
/// Calls XyPlorer Functions via commandline option '/feed=' and get result back via registered wnd message pump using WM_COPYDATA.
/// </summary>
/// <param name="script"> xyPlorer Script to call </param>
/// <returns> result string should be empty because result comes back via message pump of receiver-window using WM_COPYDATA </returns>
public static string FeedToXyPlorer(string script) {
print.it($"FeedToXyPlorer({script})");
string xyArgs = $"/feed=|{CreateXyPlorerCall(script)}|";
print.it($"run.console([out] string, {xyExe}, {xyArgs}, {xyDir}, Encoding.UTF8)");
int result = run.console(out string xyReturned, xyExe, xyArgs, xyDir, Encoding.UTF8);
print.it($"run.console([out] {xyReturned}) = {result}");
return xyReturned;
}
/// <summary>
/// Return window of running instance of xyPlorer or starting up new instance.
/// </summary>
/// <returns> Return window of xyPlorer </returns>
public static wnd GetXyplorer() {
wnd wndXyplorer = wnd.findOrRun(cn: "ThunderRT6FormDC", run: () => {
print.it($"start xyplorer");
run.it(xyExe, dirEtc: xyDir);
});
return wndXyplorer;
}
/// <summary>
/// Register window which should receive result back via WM_COPYDATA from XyPlorerCalls
/// </summary>
/// <param name="receiver"> </param>
public static void RegisterReceiver(wnd receiver) {
print.it($"RegisterReceiver({receiver})");
wndReceiver = receiver;
}
/// <summary>
/// Call xyPlorer functions and get result back via registered wnd message pump using WM_COPYDATA.
/// </summary>
/// <param name="script"> xyPlorer Script to call </param>
/// <example> prXyplorer.SendToXyPlorer("tab('get', 'path', 1)"); // gets path of first actual tab </example>
/// <returns> result string should be empty because result comes back via message pump of receiver-window using WM_COPYDATA </returns>
public static string SendToXyPlorer(string script) {
wnd w = wnd.findOrRun(of: "xyplorer.exe", run: () => run.it("xyplorer.exe"));
if (w.Is0) return "";
WndCopyData.SendReceive<char>(w, 0x00400001, CreateXyPlorerCall(script), out string receivedFromXyPlorer);
if (!string.IsNullOrEmpty(receivedFromXyPlorer)) {
print.it($"Unexpected data received from xyPlorer {receivedFromXyPlorer}");
}
return receivedFromXyPlorer;
}
private static string CreateXyPlorerCall(string commandlist) {
string result = commandlist;
if (!wndReceiver.Is0) {
result = $"::copydata '{wndReceiver.Handle}', ({commandlist}), 0;";
}
print.it($"CreateXyPlorerCall({commandlist}) = {result}");
return result;
}
#endregion Methods
}
[/code]
[code]// class "xyPlorer-Program.cs"
/*/
pr .\prXyPlorer.cs;
/*/
using System.Runtime.InteropServices;
using Au;
using Au.More;
using Au.Types;
using Microsoft.Win32;
internal partial class Program {
#region Methods
//File/directory triggers. More info in Cookbook.
private static void _FileTriggers() {
using var fw = new FileSystemWatcher(@"C:\Test");
//you can specify various filters etc
//fw.Filters.Add("*.txt");
//fw.Filters.Add("*.xml");
//fw.IncludeSubdirectories = true;
//set one or more events
fw.Created += (o, e) => { print.it($"{e.ChangeType}, {e.Name}, {e.FullPath}"); };
fw.Deleted += (o, e) => { print.it($"{e.ChangeType}, {e.Name}, {e.FullPath}"); };
fw.Renamed += (o, e) => { print.it($"{e.ChangeType}, {e.Name}, {e.OldName}"); };
fw.Changed += (o, e) => { print.it($"{e.ChangeType}, {e.Name}, {e.FullPath}"); };
//fw.Error += (o, e) => { prLog.Log(prLogMode.LogMessage, e.GetException()); };
fw.EnableRaisingEvents = true;
//using var fw2 = new FileSystemWatcher(@"C:\Another directory");
//fw2.Created += ...
// ...
//fw2.EnableRaisingEvents = true;
//then wait or execute any code. Event handlers run in another thread.
wait.ms(-1); //wait forever
//keys.waitForHotkey(0, "Esc"); //another "wait" example
//dialog.show("File change events", buttons: "Stop", x: ^0); //another "wait" example
}
//Process triggers. More info in Cookbook.
private static void _ProcessTriggers() {
foreach (var v in process.triggers()) {
print.it($"{v}");
if (v.Started)
print.it($"{process.getDescription(v.Id)}, {process.getName(v.Id, fullPath: true)}, {process.getCommandLine(v.Id)}");
}
}
//When changed screen (display monitor) count, configuration, DPI (text size, scaling), resolution or other properties.
private void _SystemEvent_DisplaySettingsChanged(object sender, EventArgs e) {
print.it($"{nameof(_SystemEvent_DisplaySettingsChanged)}({sender}, {e})");
}
//When power mode changed (battery/AC etc).
private void _SystemEvent_PowerModeChanged(object sender, PowerModeChangedEventArgs e) {
print.it($"{nameof(_SystemEvent_PowerModeChanged)}({sender}, {e})");
print.it($"PowerMode {e.Mode} Battery={computer.isOnBattery}, {Environment.CurrentManagedThreadId}");
}
//When computer suspending (sleep, hibernate) or resumed.
private void _SystemEvent_ResumeEvent(PowerModes pm) {
print.it($"{nameof(_SystemEvent_ResumeEvent)}({pm}), {Environment.CurrentManagedThreadId}");
}
//When started to log off or shutdown actually.
private void _SystemEvent_SessionEnded(object sender, SessionEndedEventArgs e) {
print.it($"{nameof(_SystemEvent_SessionEnded)}({sender}, {e})");
print.it("SessionEnded", e.Reason);
}
//When trying to log off or shutdown.
private void _SystemEvent_SessionEnding(object sender, SessionEndingEventArgs e) {
print.it($"{nameof(_SystemEvent_SessionEnding)}({sender}, {e})");
print.it("SessionEnding", e.Reason);
//e.Cancel = true;
}
//When switching user sessions, locking/unlocking the computer, etc.
private void _SystemEvent_SessionSwitch(object sender, SessionSwitchEventArgs e) {
print.it($"{nameof(_SystemEvent_SessionSwitch)}({sender}, {e})");
print.it("SessionSwitch", e.Reason);
}
//When changed some system setting. See API SystemParametersInfo.
private void _SystemEvent_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) {
print.it($"{nameof(_SystemEvent_UserPreferenceChanged)}({sender}, {e})");
print.it("UserPreferenceChanged", e.Category);
}
// https://www.libreautomate.com/forum/showthread.php?tid=7574
[Triggers]
private void ClipboardTriggers() {
var w1 = WndUtil.CreateMessageOnlyWindow(static nint (wnd w, int msg, nint wp, nint lp) => {
switch (msg) {
case Api.WM_CLIPBOARDUPDATE:
print.it("WM_CLIPBOARDUPDATE trigger");
//if want to get clipboard text, do it with a delay, else it may interfere with other clipboard programs or scripts
//timer.after(100, _ => {
// var s = clipboard.text;
// prLog.Log(prLogMode.LogMessage, s);
//});
break;
case Api.WM_COPYDATA:
// SR-COPYDATA receive WM_COPYDATA from external program
print.it($"WM_COPYDATA trigger {w} {wp} {lp}");
WndCopyData copyData = new WndCopyData(lp);
string receivedData = copyData.GetString();
print.it($"WM_COPYDATA received '{receivedData}'");
break;
case Api.WM_EXITMENULOOP:
print.it("WM_EXITMENULOOP trigger");
break;
case Api.WM_COMMAND:
print.it($"WM_COMMAND trigger {w} {wp} {lp}");
break;
default:
print.it($"OtherTriggers {msg}");
break;
}
return Api.DefWindowProc(w, msg, wp, lp);
}, "#32770");
// register xyPlorer
prXyplorer.RegisterReceiver(w1);
Api.AddClipboardFormatListener(w1);
}
[Triggers]
private void OtherTriggers() {
//Add other triggers here. More info in Cookbook.
//Click the Run button to apply changes after editing.
computer.suspendResumeEvent += _SystemEvent_ResumeEvent;
SystemEvents.PowerModeChanged += _SystemEvent_PowerModeChanged;
SystemEvents.DisplaySettingsChanged += _SystemEvent_DisplaySettingsChanged;
SystemEvents.UserPreferenceChanged += _SystemEvent_UserPreferenceChanged;
SystemEvents.SessionEnding += _SystemEvent_SessionEnding;
SystemEvents.SessionEnded += _SystemEvent_SessionEnded;
SystemEvents.SessionSwitch += _SystemEvent_SessionSwitch;
//note: all above event handler functions run in other thread.
}
#endregion Methods
#region Classes
private unsafe class Api : NativeApi {
#region Fields
// CLIPBOARD
internal const int WM_CLIPBOARDUPDATE = 0x31D;
internal const int WM_COMMAND = 0x0111;
internal const int WM_CONTEXTMENU = 0x007B;
// COPYDATA
internal const int WM_COPYDATA = 0x004A;
internal const int WM_DDE_EXECUTE = 0x03E8;
// DDE
internal const int WM_DDE_INITIATE = 0x03E0;
internal const int WM_DDE_TERMINATE = 0x03E1;
// MENU
internal const int WM_EXITMENULOOP = 0x0212;
#endregion Fields
#region Methods
[DllImport("user32.dll")]
internal static extern bool AddClipboardFormatListener(wnd hwnd);
[DllImport("user32.dll", EntryPoint = "DefWindowProcW")]
internal static extern nint DefWindowProc(wnd hWnd, int msg, nint wParam, nint lParam);
#endregion Methods
}
[AttributeUsage(AttributeTargets.Method)] private class ToolbarsAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Method)] private class TriggersAttribute : Attribute { }
#endregion Classes
}
[/code]