Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Remote contol of XYplorer
#2
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:
  1. Messages from LA to xyPlorer like your code-snippet does
  2. Using commandline option /feed= of xyPlorer which my class also implements
Either calls FeedToXyPlorer and SendToXyPlorer are prepared to receive back results from xyPlorer to a registered window as messages coming in via WM_COPYDATA as shown in enclosed sample partial Program class.

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:
Copy      Help
[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:
Copy      Help
[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]


Messages In This Thread
Remote contol of XYplorer - by MBaas - 03-03-2024, 01:40 PM
RE: Remote contol of XYplorer - by AutoStarter - 03-05-2024, 08:25 AM
RE: Remote contol of XYplorer - by MBaas - 03-05-2024, 09:31 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)