How to read left/right panel path from external application?

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: white, Hacker, petermad, Stefan2

Post Reply
jackhab
Junior Member
Junior Member
Posts: 35
Joined: 2008-03-05, 09:36 UTC

How to read left/right panel path from external application?

Post by *jackhab »

I'm writing a utility (not a plugin) which needs to read current TC panel paths.

I know I can do it via 2029 and 2030 messages which copy paths to clipboard, but since I'm doing it periodically I prefer not to use clipboard (I suspect backing up and restoring clipboard every second will not work reliably).

Is there any alternative way for external application to extract panel paths from TC?
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Re: How to read left/right panel path from external application?

Post by *ghisler(Author) »

You can send a WM_COPYDATA message to the main Total Commander window to get back various data (mostly also via WM_COPYDATA):

25.11.11 Added: Send WM_COPYDATA with dwData='G'+256*'W': Same as with 'G'+256*'A', but data is returned as UTF-16 Unicode. dwData of return is 'R'+256*'W' (32/64)
25.11.11 Added: Send WM_COPYDATA with dwData='G'+256*'A' and lpData pointing to command to get back WM_COPYDATA with various info. Supported commands A: Active side (returns L or R), or two byte command: first byte: L=left, R=right, S=source, T=target. Second byte: P=current path, C=list count, I=caret index, N=name of file under caret. dwData of return is 'R'+256*'A' (32/64)

So you send WM_COPYDATA with one of the above dwData values and lpData the command LP for the left path, and get back a WM_COPYDATA with dwData set to RA or GA and lpData the left path. Use RP for the right path etc.
Author of Total Commander
https://www.ghisler.com
User avatar
Stefan2
Power Member
Power Member
Posts: 4159
Joined: 2007-09-13, 22:20 UTC
Location: Europa

Re: How to read left/right panel path from external application?

Post by *Stefan2 »

Here
https://ghisler.ch/board/viewtopic.php?p=310263#p310263
we have tested this stuff with AutoHotkey.

For example:

;//Calling the code with some examples
vActivePanel := TC_SendData("A")
vLeftPath := TC_SendData("LP")
vLeftItemCount := TC_SendData("LC") ;incl. up dir ..
vLeftCurrentItemIndex := TC_SendData("LI")
vLeftCurrentName := TC_SendData("LN")




HTH somehow
 
jackhab
Junior Member
Junior Member
Posts: 35
Joined: 2008-03-05, 09:36 UTC

Re: How to read left/right panel path from external application?

Post by *jackhab »

Christian and Stefan2, thanks for the tips!

Maybe my question is becoming somewhat "stackoverflowish"... It's my first time writing unmanaged C# and I hope someone would be able to help me.

I couldn't get the data from the WM_COPYDATA message and I'm sure there's something wrong with my code, which I based on C# TCUtils example.

I first tested that my application can communicate with TC by successfully sending sendChangeDirectory() from the example. Then I added the following code to read current directory from TC.

Code: Select all

        public static string getDirectory()
        {
            IntPtr targetWindow = NativeMethod.FindWindow("TTOTAL_CMD", null);
            if (targetWindow == IntPtr.Zero)
                return "No TC";
            byte[] commandBuf = new byte[1000];
            Encoding.ASCII.GetBytes("LP").CopyTo(commandBuf, 0);
            IntPtr commandPtr = Marshal.AllocHGlobal(commandBuf.Length);
            try
            {
                Marshal.Copy(commandBuf, 0, commandPtr, commandBuf.Length);
                COPYDATASTRUCT copyStruct = new COPYDATASTRUCT(); ;
                copyStruct.dwData = new IntPtr((byte)'G' + 256 * (byte)'W');
                copyStruct.cbData = 3;
                copyStruct.lpData = commandPtr;
                NativeMethod.SendMessage(targetWindow, WM_COPYDATA, (IntPtr)null, ref copyStruct);
                string lpData = Marshal.PtrToStringAuto(copyStruct.lpData, commandBuf.Length);
                Debug.Print(lpData);
                return lpData;
            }
            finally
            {
                Marshal.FreeHGlobal(commandPtr);
            }
            return "N/A";
        }
Is it really needed to preallocate a buffer for lpData response? Is cdData correct? Can someone,please, explain me what am I doing wrong?
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Re: How to read left/right panel path from external application?

Post by *ghisler(Author) »

WM_COPYDATA is one way - you can only send blocks of data, you can't receive them. So what happens is that TC is sending back another WM_COPYDATA message to your app (to the window you provide in dwData) with the path in lpData.

Maybe using another approach is easier for you:
1. Send WM_USER+50 to the Total Commander main window with wparam set to 1 for left or 2 for right window
-> the return value of SendMessage is the window handle of the left path/right path.
2. Call GetWindowTextW with the received window handle to get the left/right path and display filter.
Author of Total Commander
https://www.ghisler.com
jackhab
Junior Member
Junior Member
Posts: 35
Joined: 2008-03-05, 09:36 UTC

[SOLVED] How to read left/right panel path from external application?

Post by *jackhab »

Christian

Reading path control text is, indeed, much simpler solution and I got it running in minutes. I just wanted to make a small correction: the path text should come from path control, not the window (at least this is what worked for me), so the message parameters should be 9 and 10 instead of 1 and 2.

Here is my code in case anyone interested in getting panel paths in C#.

Code: Select all

[SuppressUnmanagedCodeSecurity]
internal class Native
{
    public const int WM_USER = 0x0400;

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern int GetWindowTextW(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
}

public enum Side
{ 
    LEFT,
    RIGHT,
};

private static IntPtr GetTcWindowHandle() => Native.FindWindow("TTOTAL_CMD", null);

        private string GetTcPanelPath(Side side)
        {
            IntPtr hWnd = GetTcWindowHandle();
            if (hWnd == IntPtr.Zero)
                return null;

            var text = new StringBuilder(1024);
            IntPtr hPanel = Native.SendMessage(hWnd, Native.WM_USER + 50, (IntPtr)side, IntPtr.Zero);
            Native.GetWindowTextW(hPanel, text, text.Capacity);
            string path = text.ToString();           

            //trim trailing wildcards (from last \ till EOL)
            path = Regex.Replace(path, @"\\[^\\]+$", "\\");

            return path;
        }
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Re: How to read left/right panel path from external application?

Post by *ghisler(Author) »

Sorry, you are indeed right, 1 and 2 are for the two list windows.
Author of Total Commander
https://www.ghisler.com
Post Reply