Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

English support forum

Moderators: white, Hacker, petermad, Stefan2

Post Reply
diopter
Junior Member
Junior Member
Posts: 31
Joined: 2017-02-02, 06:42 UTC
Location: Germany

Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

Post by *diopter »

Since no one has done so yet (or at least not published),
I have decided to collate all information about the possibilities in the TC with WM_COPYDATA, WM_USER+50 and WM_USER+51 and to write down (hopefully) comprehensible.
Since I did not want to publish the info untested, and also to show the AHK friends here how easy it can be in a proper programming language,
I also wrote a small Delphi-Unit (without information only 39 lines) and a test program:
2022-05-02: Update to TC10.50b2

Code: Select all

Infos about TC command interface (TC9.00 or higher) ==========================
Commands with WM_COPYDATA: ( [ ] is optional )
 CmdType='EM': user commands em_xyz or internal commands cm_xyz
  Syntax for CmdStr: 'em_xyz[ <parameters>]'#0 or 'cm_xyz[ <parameters>]'#0
     <parameters> with '?' as first char: TC will ask user
  Internal commands with parameters: (see also WM_USER+51)
   cm_SrcViewModeList=333: [<viewmode>] - view mode menu for source (active) panel
      <viewmode>: Name of view mode or 1-based index in view mode list
                  (use cm_SrcViewMode0=8500 for default view mode)
   cm_LeftViewModeList=133: [<viewmode>] - view mode menu for left panel
      <viewmode>: Name of view mode or 1-based index in view mode list
   cm_RightViewModeList=233: [<viewmode>] - view mode menu for right panel
      <viewmode>: Name of view mode or 1-based index in view mode list
   cm_List=903: <filename> - View the file with Lister
   cm_ListOnly=2934, cm_ListInternalOnly=1006: <filename> - View the file with Lister (from TC10.00b5)
   cm_ListMulti, cm_ListInternalMulti:
      Does NOT!!! work with <filename>, always shows file under cursor like F3 / Alt+F3
  Example: 'em_AppendTabs c:\my.tab'#0
 CmdType='CD': change dir(s)
  Syntax for CmdStr: ( ['T'] open in new Tab )
   [#$EF#$BB#$BF]['<left_path>']#13[#$EF#$BB#$BF]['<right_path>'][#0'T']#0
   [#$EF#$BB#$BF]['<source_path>']#13[#$EF#$BB#$BF]['<target_path>']#0'S'['T']#0
       (#$EF#$BB#$BF = Unicode UTF-8 BOM,  #13 = \r = CR = carriage return)
  Examples:
   'c:\tc'#13'd:\data'#0   : Left changed to c:\tc , Right changed to c:\data
   'c:\tc'#13'#0           : Left changed to c:\tc , Right unchanged
   '#13'd:\data'#0         : Left unchanged        , Right changed to c:\data
   'c:\tc'#13'd:\data'#0'T'#0  : Left new Tab c:\tc , Right new Tab c:\data
   'c:\tc'#13'd:\data'#0'S'#0  : Source changed to c:\tc , Target changed to c:\data
   'c:\tc'#13'd:\data'#0'ST'#0 : Source new Tab c:\tc , Target new Tab c:\data
Info requests with WM_COPYDATA:  since TC8.0b10
 CmdType='GA' for ANSI or 'GW' for UTF-16 Unicode answer
  Syntax for CmdStr: 'A'#0  : Active panel (returns 'L' or 'R')
                     '<panel><question>'#0
   <panel>   : 'L'=left, 'R'=right, 'S'=source, 'T'=target
   <question>: 'P'=current path, 'C'=list count, 'I'=caret index,
               'N'=name of file under caret
  Examples: 'SN'#0 : Name of the focused file in the active panel
            'SP'#0 : Current path in the active (source) pane
            'TP'#0 : Current path in the target panel
  Answer: WM_COPYDATA message with
             CmdType='RA' for ANSI or 'RW' for UTF-16 Unicode answer
             CmdLen: Length of CmdStr
             CmdStr: contains the answer string
Internal commands with WM_USER+51 (1075, $433. 0x433): ( [] is optional )
 wparam: numeric value of cm_xyz internal command
 lparam: [<parameter>]
  Commands with <parameter> :  most since TC9.0b
   CM_WAIT=-12: <ms> - Wait ms milliseconds
   cm_100Percent=910: <width%> - Moves panel separator to width% (percent) of TC window width
                      <width%>: -1..-100 = left panel to width%
                                 0..100  = active (source) panel to width% (0=100%)
   cm_Select=2936: [<itemcount>] - Select <itemcount> file(s) from cursor, go to next
   cm_UnSelect=2937: [<itemcount>] - Remove selection of <itemcount> file(s), go to next
   cm_Reverse=2938: [<itemcount>] - Reverse selection of <itemcount> file(s), go to next
   cm_GoToFirstEntry=2049: [<itemindex>] - Place cursor on <itemindex>+1 folder or file
                    (zero based, 0 = go to first folder or file)
   cm_GoToFirstFile=2050: [<itemindex>] - Place cursor on <itemindex>+1 file
                    (zero based, 0 = go to first file)
   cm_Delete=908: <???> - Delete files (!!!TC9.21a: does always the same as the Del key!!!)
   cm_LeftSwitchToThisCustomView=5510: [<colmode>] - Custom columns mode for left panel
      <colmode>: 0 = TCdefault, else = what you see in Show / Custom columns mode
   cm_RightSwitchToThisCustomView=5511: [<colmode>] - Custom columns mode for right panel
      <colmode>: 0 = TCdefault, else = what you see in Show / Custom columns mode
   cm_SearchForInCurdir=517: [<drive>] - Opens Search in directory under the cursor
      <drive>: numeric value of drive letter (#'A'=65, #'C'=67 ...)
           if <drive> is a valid value, search starts in the root of this drive
   cm_DirectoryHotlist=526: [<position>] - Directory popup menu
              <position>: 1 = mouse pointer pos, 2 = right panel, 3 = left panel
   cm_SrcOpenDrives=331: [<drive>] - Opens source (active) drive list
      <drive>: numeric value of drive letter (#'A'=65, #'C'=67 ...#'Z') or
               #'/'=47:root, #'.'=46:parent dir, #'['=91:nethood
           if <drive> is a valid value, the drive will be changed without showing the list
   cm_LeftOpenDrives=131: [<drive>] - Opens left drive list
      <drive>: numeric value of drive letter (#'A'=65, #'C'=67 ...#'Z') or
               #'/'=47:root, #'.'=46:parent dir, #'['=91:nethood
           if <drive> is a valid value, the drive will be changed without showing the list
   cm_RightOpenDrives=231: [<drive>] - Opens right drive list
      <drive>: numeric value of drive letter (#'A'=65, #'C'=67 ...#'Z') or
               #'/'=47:root, #'.'=46:parent dir, #'['=91:nethood
           if <drive> is a valid value, the drive will be changed without showing the list
   cm_VerticalPanels=305: [<state>] - File windows above each other
      <state>: 0=toggle, 1=true, 2=false
   cm_*Thumbs, cm_*NegOrder: (* stands for Left, Right and Src)
      <state>: 0=toggle, 1=true, 2=false
   cm_*ByName, cm_*ByExt, cm_*BySize, cm_*ByDateTime: (* stands for Left, Right and Src)
      <state>: 0 = toggle direction, 1 = in ascending order, 2 = in descending order,
               3 = by THIS column (reverses direction),
               4 = additionally sort by THIS column if it is already sorted
                   by another column (reverses direction),
               5 as 4, but sorted in ascending order,
               6 as 4, but sorted in descending order
   cm_SrcViewModeList=333: [<viewmode>] - view mode menu for source (active) panel
      <viewmode>: 1-based index in view mode list (0 = default view mode)
   cm_LeftViewModeList=133: [<viewmode>] - view mode menu for left panel
      <viewmode>: 1-based index in view mode list (0 = default view mode)
   cm_RightViewModeList=233: [<viewmode>] - view mode menu for right panel
      <viewmode>: 1-based index in view mode list (0 = default view mode)
   cm_rereadsource=540: [<mode>]:  (from TC9.50b9)
      1: forces refresh even if nothing has changed in that directory, e.g. to re-load icons and overlays
      2: re-applies automatic view mode change to current directory
      3: 1+2
   cm_*Comments, cm_*DirBranch, cm_*DirBranchSel, cm_ToggleAutoViewModeSwitch,
   cm_SyncChangeDir, cm_SwitchLongNames, cm_SwitchHidSys, cm_SwitchHid, cm_SwitchSys,
   cm_Switch83Names, cm_FtpHiddenFiles, cm_SwitchDirSort, cm_SwitchOverlayIcons,
   cm_SwitchWatchDirs, cm_SwitchIgnoreList, cm_SwitchX64Redirection, cm_Vis*: (from TC10.00b1)
      [<state>]: 0=toggle, 1=set, 2(or -1)=reset
   cm_ZoomIn=2953, cm_ZoomOut=2954: [<percent>]: Zoom thumbnails in 10% steps between 10% and 200% (from TC10.00b1)
   cm_*Quickview, cm_*QuickInternalOnly: (* stands for Left, Right and Src) (from TC10.00b2)
      [<state>]: 0=toggle, 1=set, 2(or -1)=reset
   cm_SeparateQuickview=2941, cm_SeparateQuickInternalOnly=2942: (from TC10.00b2)
      [<state>]: 0=toggle, 1=set, 2(or -1)=reset
   cm_CloseCurrentTab=3007: [<type>]: 1=close locked tab without confirmation (from TC10.50b1)
   cm_CloseAllTabs=3008: [<type>]: 1=close unlocked tabs without confirmation,
                                   2=close also locked tabs with confirmation,
                                   3=close also locked tabs without confirmation
   cm_UnloadPlugins=2913: <type>: 0=unload all types, or sum of: 1=packer, 2=file system, 4=lister, 8=content plugins
   cm_SwitchColorsByFileType=2957: <state>: 0=toggle, 1=on, 2(or -1)=off
   cm_SwitchFileTipWindows=2959: enable/disable showing tooltips (hints) for files (from TC10.50b1):
      <state>: 0=toggle, 1=on, 2(or -1)=off
   cm_SaveHdrDetailsToFile=2093, cm_SaveHdrDetailsToFileA=2094, cm_SaveHdrDetailsToFileW=2095,
   cm_CopyFileDetailsToClip=2036, cm_CopyFpFileDetailsToClip=2037, cm_CopyHdrFileDetailsToClip=2090,
   cm_CopyHdrFpFileDetailsToClip=2091, cm_CopyHdrNetFileDetailsToClip=2092,
   cm_CopyNetFileDetailsToClip=2038 in normal, comments, and custom columns view (from TC10.50b1):
      [<columns>]: 0=all, 1=name+ext, 2=first custom, 4=second custom, 8=third custom etc. (Sum)
      ### Bugs in TC10.50b2: 1 does same as 0,  cm_CopyFileDetailsToClip copies headers too
 Examples: SendMessage(TC_hwnd, WM_USER+51, cm_CopySrcPathToClip, 0);
           PostMessage(TC_hwnd, WM_USER+51, cm_SrcOpenDrives, #'A');
Info requests with WM_USER+50 (1074, $432):  since TC9.0b
 wparam: <parameter>
     1: returns window handle of control: leftlist,
     2: returns window handle of control: rightlist,
     3: returns window handle of control: active list,
     4: returns window handle of control: inactive list,
     5: returns window handle of control: leftheader,
     6: returns window handle of control: rightheader,
     7: returns window handle of control: leftsize,
     8: returns window handle of control: rightsize,
     9: returns window handle of control: leftpath,
    10: returns window handle of control: rightpath,
    11: returns window handle of control: leftinfo,
    12: returns window handle of control: rightinfo,
    13: returns window handle of control: leftdrives,
    14: returns window handle of control: rightdrives,
    15: returns window handle of control: leftpanel,
    16: returns window handle of control: rightpanel,
    17: returns window handle of control: bottompanel,
    18: returns window handle of control: lefttree,
    19: returns window handle of control: righttree,
    20: returns window handle of control: cmdline,
    21: returns window handle of control: curdirpanel,
    22: returns window handle of control: inplaceedit,
    23: returns window handle of control: splitpanel,
    24: returns window handle of control: leftdrivepanel,
    25: returns window handle of control: rightdrivepanel,
    26: returns window handle of control: lefttabs,
    27: returns window handle of control: righttabs,
    28: returns window handle of control: buttonbar,
    29: returns window handle of control: buttonbarvertical,
  1000: get active panel, result: 1=left, 2=right,
  1001/1002: get number of items in left/right list,
  1003/1004: get total number of items (including those hidden by quick filter),
  1005/1006: get total number of selected items,
  1007/1008: get index of current item (caret),
  1009/1010: get index of first item (0 if there is no updir, 1 otherwise),
  1011/1012: get index of first file in list (-1 if there are no files)
================================================================================}

unit TCcmd;
interface uses Windows, Messages;

type
  TChArr4 = array[1..4] of char;
  TTCcmdDATASTRUCT = packed record
    CmdType: TChArr4;  // dwData: DWORD;
    CmdLen : DWORD;    // Length of CmdStr, including terminating #0
    CmdPtr : Pointer;  // Pointer to CmdStr
  end;

const CmdGA: TChArr4 = 'GA'#0#0;      CmdGW: TChArr4 = 'GW'#0#0;
      CmdEM: TChArr4 = 'EM'#0#0;      CmdCD: TChArr4 = 'CD'#0#0;
      UTF8BOM : array[0..2] of char = #$EF#$BB#$BF;

function TCrequest(CM_Req: Integer): Integer;
function TCcommand(CM_Cmd: Integer; Param: Integer=0): Integer; overload;// if Param < 0 ---> PostMessage
function TCcommand(const aCmdType: TChArr4; const CmdStr: AnsiString): Integer; overload;
var TCwnd, AnswerWnd: THandle; // Wnd handles has to be initialized from main prog

implementation

function TCrequest(CM_Req: Integer): Integer;
begin Result := SendMessage(TCwnd, WM_USER+50, CM_Req, 0) end;

function TCcommand(CM_Cmd: Integer; Param: Integer = 0): Integer;
begin // if Param < 0 ---> PostMessage
 if Param >= 0 then Result := SendMessage(TCwnd, WM_USER+51, CM_Cmd, Param)
 else Result := Integer(PostMessage(TCwnd, WM_USER+51, CM_Cmd, -Param))
end;

function TCcommand(const aCmdType: TChArr4; const CmdStr: AnsiString): Integer;
var TCcmdDATASTRUCT: TTCcmdDATASTRUCT;
begin
 with TCcmdDATASTRUCT do
   begin CmdType:= aCmdType;  CmdLen:= Length(CmdStr)+1;  CmdPtr:= @CmdStr[1] end;
 Result := SendMessage(TCwnd, WM_COPYDATA, AnswerWnd, lparam(@TCcmdDATASTRUCT));
end;
end.
Test program:

Code: Select all

unit TCcmdTestU1;

interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls, TCcmd, Hex;

type
  TTCcmdForm = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
  public
  end;

var TCcmdForm: TTCcmdForm;

implementation
{$R *.dfm}

{$I TotalCmds.inc}

procedure TTCcmdForm.FormShow(Sender: TObject);
begin
 AnswerWnd := Self.WindowHandle;   TCwnd := FindWindow('TTOTAL_CMD', nil);
 if TCwnd = 0 then Label1.Caption := 'Kein TTOTAL_CMD';
 Left := 0;  Top := 0;
end;

procedure TTCcmdForm.WMCopyData(var Msg: TWMCopyData);
begin
  Label1.Caption := PChar(Msg.CopyDataStruct.lpData);
  Msg.Result  := 1;
end;

procedure TTCcmdForm.Button1Click(Sender: TObject);
begin
// TCcommand(CmdEM, 'em_Test');
// TCcommand(CmdGA, 'SN');
// TCcommand(CmdCD, '\'#13'D:\');
// TCcommand('EM', 'Test');
 TCcommand(CmdEM, 'cm_LeftSwitchToThisCustomView Filme');
end;

procedure TTCcmdForm.Button2Click(Sender: TObject);
begin
 Label1.Caption := IntToStr(TCcommand(cm_FocusLeft));
 TCcommand(cm_GoToFirstEntry, 1) 
end;

procedure TTCcmdForm.Button3Click(Sender: TObject);
begin
 TCcommand(cm_FocusRight);
 Label1.Caption := IntToStr(TCcommand(cm_GoToFirstEntry, 2))
end;

procedure TTCcmdForm.Button4Click(Sender: TObject);
begin
// Label1.Caption := IntToStr(TCrequest(1003)) //get total number of items
// TCcommand(cm_SrcViewModeList, 1);
// TCcommand(cm_LeftSwitchToThisCustomView, 2);
 TCcommand(CmdEM, 'em_Test1 "C:\Delphi7\ Neu\Uwe\xx.txt"');  //
end;

procedure TTCcmdForm.Button5Click(Sender: TObject); // Get all selected filenames
var LBwnd: THandle;   I, J, L, N: Integer;      S: AnsiString;
    IntArr: array[1..100] of Integer;
begin
 LBwnd := TCrequest(1); // returns window handle of control: leftlist
 N := SendMessage(LBwnd, LB_GETSELITEMS, High(IntArr), lparam(@IntArr));
 SetLength(S, 2048*10);  L := 0;
 for I := 1 To N do
 begin
  if L > Length(S)-2048 then SetLength(S, Length(S) + 2048*10);
  J := SendMessage(LBwnd, LB_GETTEXT, IntArr[I], lparam(@S[L+1]));
  Inc(L, J);   S[L+1] := #10;   Inc(L);
 end;
 SetLength(S, L-1);
 Label1.Caption := S;
end;

end.
If someone finds errors or has more information, I would be happy to hear from you.
Last edited by diopter on 2022-05-03, 23:18 UTC, edited 3 times in total.
Pawel
Junior Member
Junior Member
Posts: 82
Joined: 2018-12-18, 11:54 UTC
Location: Poland
Contact:

Re: Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

Post by *Pawel »

Hi,
Very nice idea!
The example code you paste here is incomplete - could you attach here full code with some more comments?

Could you please write some example (in Delphi) how to use WM_COPYDATA message with TC?
Yes, there is a description in your example unit, but I can not make it work...

For example, below lines:

Code: Select all

TCcommand(CmdEM, 'em_Test'); // -> what is em_Test?
TCcommand(CmdGA, 'SN'); // 'SN' -> It should return Name of the focused file in the active panel?
TCcommand(CmdCD, '\'#13'D:\'); // -> This should set root dir for left and D:\ for right panel, right?
TCcommand('EM', 'Test'); // - ? 


How to make it work?

Or, Below function:

Code: Select all

function TCcommand(const aCmdType: TChArr4; const CmdStr: AnsiString): Integer;
var TCcmdDATASTRUCT: TTCcmdDATASTRUCT;
begin
 with TCcmdDATASTRUCT do
   begin CmdType:= aCmdType;  CmdLen:= Length(CmdStr)+1;  CmdPtr:= @CmdStr[1] end;
 Result := SendMessage(TCwnd, WM_COPYDATA, AnswerWnd, lparam(@TCcmdDATASTRUCT));
end;
Why AnswerWnd handle is Self.WindowHandle?
What is the result of this function?
I guess WMCopyData(var Msg: TWMCopyData); procedure should get data we want, right(I have no data in label1.caption)?

Or, in this procedure:

Code: Select all

procedure TForm1.Button5Click(Sender: TObject);
var
   LBwnd: THandle;
   I, J, L, N: Integer;
   S: AnsiString;
   IntArr: array[1..100] of Integer;
begin
   LBwnd := TCrequest(1); // returns window handle of control: leftlist
   N := SendMessage(LBwnd, LB_GETSELITEMS, High(IntArr), lparam(@IntArr));
   SetLength(S, 2048*10);
   L := 0;
   for I := 1 To N do
      begin
         if L > Length(S)-2048 then SetLength(S, Length(S) + 2048*10);
         J := SendMessage(LBwnd, LB_GETTEXT, IntArr[I], lparam(@S[L+1]));
         Inc(L, J);   S[L+1] := #10;   Inc(L);
      end;
   SetLength(S, L-1);
   Label1.Caption := S;
end;
It works fine, but is it possible to get only full path of selected entries in chosen panel?
(this example gets all data, with size, extension or attributes)

As you can see there are plenty of questions :)
-Pawel
User avatar
MVV
Power Member
Power Member
Posts: 8702
Joined: 2008-08-03, 12:51 UTC
Location: Russian Federation

Re: Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

Post by *MVV »

Perhaps it would be better to have such things in TC wiki. :wink:
diopter
Junior Member
Junior Member
Posts: 31
Joined: 2017-02-02, 06:42 UTC
Location: Germany

Re: Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

Post by *diopter »

Update Post #1 to TC10.50b2
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48021
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Re: Collected infos about WM_COPYDATA, WM_USER+50 and WM_USER+51 in TC

Post by *ghisler(Author) »

Here are instructions in the Wiki on how how to send a command with AutoHotkey:
https://www.ghisler.ch/wiki/index.php?title=AutoHotkey:_Send_a_user_command_to_Total_Commander
Author of Total Commander
https://www.ghisler.com
Post Reply