Sind ''Automatisierung'' und ''Macros'' im TC möglich?

German support forum

Moderators: white, Hacker, Stefan2

Pauli
Junior Member
Junior Member
Posts: 24
Joined: 2010-01-13, 08:22 UTC

Post by *Pauli »

@Dalai:
Danke, das Kommando für den Admin start habe ich mir gleich mal angelegt. Allerdings hatte ich den TC aktuell sowieso immer als Admin laufen.

Sollte man dies nicht machen? Nur so kann ich Problemlos unter Win 10 im Programm Ordner werkeln und auch meine Scripte laufen dort?!

Die Scripte machen nix wildes, sie erleichtern mir nur die Arbeit und in diesem Fall wird das Verzeichnis umbenannt und bekommt inkl. aller Unterverzeichnisse bzw. Dateien ein paar Attribute (hidden etc.) gesetzt.

genauso habe ich Scripte, die eine markierte Datei in bestimmte Zielordner kopiert bzw. verschiebt. So was macht doch mit dem MUT nicht wirklich Sinn oder?


@Stefan2: Super + Danke, hört sich sehr interessant an und werde ich mir mal genauer anschauen! Du empfiehlst im Zusammenspiel mit TC eher AutoHotkey oder bekomme ich das 'Fernsteuern' vom TC auch mit Powershell hin (kenne ich halt schon ganz gut)?

Gruß, Pauli
User avatar
Stefan2
Power Member
Power Member
Posts: 4133
Joined: 2007-09-13, 22:20 UTC
Location: Europa

PowerShell: SendMessage TC fernsteuern

Post by *Stefan2 »

Zum Fernsteuern des TCs muss das Skriptingtool deiner Wahl die "sendmessage" Funktion beherrschen.

Mit PoSh habe ich das noch nicht ausprobiert, aber mittels Zugriff auf die WindowsTM API ist alles möglich, dass hier habe ich gerade gefunden:

Code: Select all

#Add the SendMessage function as a static method of a class
$SendMessage = Add-Type -MemberDefinition $signature -Name "Win32SendMessage" -Namespace Win32Functions -PassThru
#Invoke the SendMessage Function
$SendMessage::SendMessage($HWND, $WM_SYSCOMMAND, $SC_MONITORPOWER, $MONITOR_OFF)
https://misterhenson.wordpress.com/tag/powershell/

Diese Syntax beruht wahrscheinlich auf https://msdn.microsoft.com/de-de/library/windows/desktop/ms644950%28v=vs.85%29.aspx

Diese muss man jetzt nur noch verstehen und anpassen (Trial&Error)

Wie gesagt, das HardwareHandle 'TTOTAL_CMD', der Kanal 'WM_USER+50 = 1074' bzw. 'WM_USER+51 = 1075' sowie die Befehle in der 'TOTALCMD.INC' sind bekannt.


Zum Beispiel NirCmd
nircmdc.exe win sendmsg class TTOTAL_CMD 1075, 540, 0

Und AutoHotkey
SendMessage 1074, 1011, 0, , ahk_class TTOTAL_CMD



Wie das bei PoSh funktioniert, muss man noch eruieren.




Upps.

Gerade in meinem TC-Ordner gefunden, ...habe ich anscheinend schon mal ausprobiert:

Code: Select all

# 21.03.2016

$Handle =  (Get-Process TOTALCMD).MainWindowHandle
$TCmsg = 1075
$TCparam = 690
"hWnd $Handle  /  hMsg $TCmsg  /  wParam $TCparam"

$PostMessage = Add-Type -MemberDefinition @"
[DllImport("user32.dll")] public static extern int PostMessage(int hWnd, int hMsg, int wParam, int lParam); 
"@ -Name "Win32PostMessageF" -Namespace Win32Functions -PassThru 
$PostMessage::PostMessage($Handle, 1075, $TCparam, 0)

#Post will NOT wait

Code: Select all

$Handle =  (Get-Process TOTALCMD).MainWindowHandle
$TCmsg = 1075
$TCparam = 690
"hWnd $Handle  /  hMsg $TCmsg  /  wParam $TCparam"

$SendMessage = Add-Type -MemberDefinition @"
[DllImport("user32.dll")] public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam); 
"@ -Name "Win32SendMessage" -Namespace Win32Functions -PassThru 
$SendMessage::SendMessage($Handle, 1075, $TCparam, 0)

#Send WILL wait

Code: Select all


#usage: TC 2033
#TOTALCMD.INC: cm_LoadSelectionFromClip=2033;Read file selection from clipboard


Function TC($TCparam) {
if ("Win32Functions.Win32PostMessage" -as [type]) {"Win32PostMessage is loaded"}else{"Win32PostMessage not loaded yet"}
$Handle =  (Get-Process TOTALCMD).MainWindowHandle
$PostMessage = Add-Type -MemberDefinition @"
[DllImport("user32.dll")] public static extern int PostMessage(int hWnd, int hMsg, int wParam, int lParam); 
"@ -Name "Win32PostMessage" -Namespace Win32Functions -PassThru 
if ("Win32Functions.Win32PostMessage" -as [type]) {"Win32PostMessage is loaded now"}else{"Win32PostMessage not loaded yet"}
$PostMessage::PostMessage($Handle, 1075, $TCparam, 0)
}


#To unload an existing type from a PowerShell session is not possible, you will not to restart the PowerShell process or fire up a new instance.
#This issue isn't a PowerShell limitation so much as it is a .NET limitation. There's no supported way to remove assemblies once they have been loaded. – Keith Hill Sep 8 '14 at 21:22 


# TEST

# Button:
# CMD: this script.ps1
# PARAM: '%L'  3


# this Script.ps1:

$TCListe = $Args[0]
$TCListe = Get-Content $TCListe

$WantedAmount = $Args[1]
if (!$WantedAmount){$WantedAmount=10} "Wanted amount is: $WantedAmount"

$WantedFiles = $TCListe | select -first $WantedAmount
$WantedFiles | clip

#Execute my TC function:
#cm_About=690;Help/About Total Commander
#cm_ClearAll=524;Unselect all 
#cm_LoadSelectionFromClip=2033;Read file selection from clipboard
#cm_ExchangeSelection=525;Invert selection
TC 2033



Bei Bedarf bitte mal austesten...

Aber AutoHotkey und NirCmd sind da handlicher, da dort diese Befehle bereits eingebaut zur Verfügung stehen.


 
User avatar
Dalai
Power Member
Power Member
Posts: 9365
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Pauli wrote:Allerdings hatte ich den TC aktuell sowieso immer als Admin laufen.

Sollte man dies nicht machen?
Nein, sollte man nicht. Alle vom TC aus gestarteten Programme haben dann ebenfalls Adminrechte. Das beinhaltet auch solche, die per Doppelklick auf irgendein Dokument gestartet werden, z.B. Textverarbeitung, Medienplayer usw.
Nur so kann ich Problemlos unter Win 10 im Programm Ordner werkeln und auch meine Scripte laufen dort?!
Eben für solche Fälle bietet es sich an, eine weitere TC-Instanz zu starten bzw. parallel laufen zu haben, die als Admin läuft. Die Unterscheidung zwischen diesen Instanzen ist u.U. nicht ganz einfach, aber auch dafür gibt's hier im Forum Beispiele zur Lösung, die mehrere verschiedene wincmd.ini nutzen und/oder Abschnitte aus dieser umleiten oder ähnliches.
genauso habe ich Scripte, die eine markierte Datei in bestimmte Zielordner kopiert bzw. verschiebt. So was macht doch mit dem MUT nicht wirklich Sinn oder?
In bestimmte Verzeichnisse zu kopieren ist damit nicht wirklich drin, wenn "bestimmte" immer ein anderes Verzeichnis meint, je nach Datei völlig unterschiedlich und nicht aus dem Dateinamen ableitbar. Ich beziehe mich hier in erster Linie auf [N], [P] und [G], die für Name, Vaterverzeichnis bzw. Großvaterverzeichnis stehen, und auf die Möglichkeit, mit [N]\[N] eine Datei in ein Verzeichnis zu verschieben, das genauso heißt wie die Datei selbst.

Es gibt da jede Menge Möglichkeiten, aber nicht alles muss man nutzen, und jeder hat eine andere Arbeitsweise. Insofern hast du die Chance der Qual der Wahl. Nutze sie ;).

Grüße
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
Pauli
Junior Member
Junior Member
Posts: 24
Joined: 2010-01-13, 08:22 UTC

Post by *Pauli »

Danke, arbeite mich aktuell mal etwas in AutoHotkey ein und schau mal was damit geht ...

Was mir nun gerade schon mal aufgefallen ist: Wenn ich %P%N als Parameter übergebe bekomme ich, bei Selektion des [..] Eintrages das entsprechende übergeordnete Verzeichnis. Wie kann ich denn Festellen, das die Selektion nicht auf dem eigentlichen Verzeichnis (einem 'normalen' Verzeichniseintrag) steht, sondern auf dem [..] Eintrag. Dann wäre nämlich ein verschieben, umbenennen etc. des Verzeichnisses blöd ...

Danke, Pauli
User avatar
Dalai
Power Member
Power Member
Posts: 9365
Joined: 2005-01-28, 22:17 UTC
Location: Meiningen (Südthüringen)

Post by *Dalai »

Sofern du nur Dateien bearbeiten willst (und keine Verzeichnisse), kannst du in deinem Skript einfach prüfen, ob der Name ein Verzeichnis ist, z.B. so:

Code: Select all

if exist %uebergebener_dateiname%\nul echo Dies ist ein Verzeichnis
bzw. entsprechendes Pendant in den anderen Skriptsprachen. Oder du übergibst dem Skript vom TC aus zusätzlich noch das Verzeichnis, in dem die Dateien liegen, z.B. %P %P%N (oder umgekehrt) und vergleichst dann auf Gleichheit

Code: Select all

if "%~1"=="%~2" echo So wird das nix
. Wahrscheinlich gibt's da noch mehr Möglichkeiten.

Grüße
Dalai
#101164 Personal licence
Ryzen 5 2600, 16 GiB RAM, ASUS Prime X370-A, Win7 x64

Plugins: Services2, Startups, CertificateInfo, SignatureInfo, LineBreakInfo - Download-Mirror
Pauli
Junior Member
Junior Member
Posts: 24
Joined: 2010-01-13, 08:22 UTC

Re: PowerShell: SendMessage TC fernsteuern

Post by *Pauli »

Stefan2 wrote: Wie gesagt, das HardwareHandle 'TTOTAL_CMD', der Kanal 'WM_USER+50 = 1074' bzw. 'WM_USER+51 = 1075' sowie die Befehle in der 'TOTALCMD.INC' sind bekannt.
 
Woher weiß ich wann ich 1074 bzw. 1075 nehmen muss und woher kommt der Wert WM_USER?

Aktuell habe ich mein bekanntes Script in AHK umgesetzt und dort wie lang vergeblich Versucht mit

Code: Select all

SendMessage 1074, 540, 0, , ahk_class TTOTAL_CMD
den Refresh auszulösen. Funktioniert hat es letztendlich nachdem ich statt 1074, die 1075 genommen habe!?


@Dalai: Ich will mein Script nur auf Verzeichnisse zulassen. Das klappt auch mit

Code: Select all

	FileGetAttrib, Attributes, %TCSelect%
	IfInString, Attributes, D
Ich willl es aber nicht durchführen, wenn ich in der normalen Ansicht auf dem [..] Eintrag (für den Sprung auf das übergeordnete Verzeichnis) stehe. Denn dann gibt %P%N zwar das übergeordnete Verzeichnis zurück, aber ich manipuliere dann ja den Ast auf dem ich sitze. Wie kann ich die verhindern bzw. ich will das Script nur ausführen, wenn in der normalen Ansicht wirklich ein Verzeichnis ausgewählt wurde?

Danke, Pauli
User avatar
Stefan2
Power Member
Power Member
Posts: 4133
Joined: 2007-09-13, 22:20 UTC
Location: Europa

Post by *Stefan2 »

WM_USER = 1024 ist ein Standard der Programmiersprache (oder so ähnlich, angefangen hat das mit 'C' und der Windows API).
WM_USER+50=1074 (und +51=1075) ist ein freigewählter Wert des Programmierers.
Welcher Wert für einen TC-Befehl genommen werden muss, findet man in der History.txt, oder im Forum, wo es User bereits ausprobiert haben.
Vieles ist historisch gewachsen und für Nichtprogrammierer ziemlich nebulös.
Am Besten googlen nach Delphi WM_USER Sendmessage Postmessage Windows-API


Ich glaube, es gibt zurzeit nur die Werte 1074 und 1075 für WM_USER.

Daneben existiert noch WM_COPYDATA, auch hier findest du Infos in der History.txt und im Forum (über Google durchsuchen).

PS X:\ToCo8> gc .\HISTORY.TXT | ?{$_ -like "*WM_*" }|out-file History_WM.txt



 
User avatar
milo1012
Power Member
Power Member
Posts: 1158
Joined: 2012-02-02, 19:23 UTC

Post by *milo1012 »

Pauli wrote:Woher weiß ich wann ich 1074 bzw. 1075 nehmen muss und woher kommt der Wert WM_USER?
1074 (also WM_USER+50) gibt nur TC-Statusinformationen zurück (und gibt es erst seit TC 9.0 IIRC), z.B.
history.txt wrote:08.06.16 Added: Send WM_USER+50 with wparam set to 1000 to get active panel: 1=left, 2=right (32/64)
1075 (also WM_USER+51) erlaubt über den "wparam"-Parameter (dritter Parameter für die WinAPI-Funktion SendMessage(), zweiter bei der AHK-Funktion) das Aufrufen von TC-Befehlen, also einem "cm_"-Befehl. Die Nummern dazu findest du, wie Stefan2 schon sagte, in der TOTALCMD.INC-Datei, in deinem Fall also z.B. 540 für cm_RereadSource.


Stefan2 wrote:WM_USER = 1024 ist ein Standard der Programmiersprache (oder so ähnlich, angefangen hat das mit 'C' und der Windows API).
*hust*.
WM_USER ist ein Typ einer "Windows Message", auf deutsch: eine Nachricht, die Windows benutzt, um ein Fenster (Window) eines Prozesses über gewisse Dinge zu informieren. Jedes registrierte Fenster hat dafür eine "Window procedure", also eine Funktion, die diese Nachrichten bearbeitet. Mit der Programmiersprache C hat das also erstmal nix zu tun, auch nicht direkt mit der API (nur indirekt, um solche Nachrichten über API-Funktionen handeln zu können), sondern mit dem Konzept des Betriebssystems Windows (und ja, andere BSe haben das in ähnlicher Form natürlich auch, allerdings muss das dann nicht unbedingt an Fenster gebunden sein). Jedenfalls kann dieses System in Windows sowohl zur Kommunikation mit verschiedenen Fenstern des eigenen Prozesses genutzt werden (z.B. wenn man durch Plugins keine eigene Kontrolle mehr über alle seine eigenen Fenster hat), als auch für die Interprozesskommunikation (engl. IPC), also Kommunikation von verschiedenen Prozessen untereinander, siehe eben AutoIt und AHK.
SCNR
TC plugins: PCREsearch and RegXtract
User avatar
Stefan2
Power Member
Power Member
Posts: 4133
Joined: 2007-09-13, 22:20 UTC
Location: Europa

Post by *Stefan2 »

>>WM_USER ist ein Typ einer "Windows Message",

und wo ist das definiert?

Ich denke mal...

In der Winuser.h ?
Also zuerst in 'C', oder?
Denn WindowsTM wurde Anfangs in 'C' geschrieben (Assembler hat nichts mit GUI zu tun, oder gibt es da Ausnahmen?)
Alle nachfolgenden Sprachen haben es sich dort abgeschaut, um kompatible zu sein.

Und entwickelt wurden diese messages für das API.


Hat einer einen Link zum Ursprung von WM_ messages?



 
User avatar
milo1012
Power Member
Power Member
Posts: 1158
Joined: 2012-02-02, 19:23 UTC

Post by *milo1012 »

[OT]
Stefan2 wrote:Ich denke mal...

In der Winuser.h ?
Also zuerst in 'C', oder?
Denn WindowsTM wurde Anfangs in 'C' geschrieben (Assembler hat nichts mit GUI zu tun, oder gibt es da Ausnahmen?)
Alle nachfolgenden Sprachen haben es sich dort abgeschaut, um kompatible zu sein.
Ich weiß wirklich nicht, wieso du an der Stelle die Verbindung mit der Programmiersprache ziehst. Ja, natürlich ist Windows und die API im C-Stil. Und natürlich ist die WM_USER irgendwo in den Windows-Headern definiert, aber das ist eben nicht die Konsequenz aus "weil in C geschrieben", sondern weil Programme, die die API nutzen wollen, eben diesen Wert wissen müssen. Windows selbst könnte in sonst einer Programmiersprache geschrieben sein, am Ende ist das Konzept selbst völlig unabhängig davon. Deine Formulierung war einfach nur unglücklich.
Denn völlig egal ob nun BS mit API oder Programm mit ABI: du musst den Leuten mitteilen, welche Werte gelten sollen. Das ist einfach die Spezifikation der Schnittstelle, unabhängig davon, wie du nun ein Programm dafür baust. Das Konzept, Nachrichten an Fenster zu koppeln, ist das Kernkonzept von Windows, völlig egal, wie es nun programmiert ist. Und Sprachen haben sich da nichts abgeschaut, das sind einfach Grundprinzipien von GUI-Programmierung und Interprozesskommunikation, die es auch schon vor Windows gab. Was du vermutlich meinst: Sprachen, die die API verwenden, müssen zu den Aufrufkonventionen kompatibel sein. Aber ansonsten ist es ziemlich egal, in welcher Sprache das BS und die Programme geschrieben sind, solange sie durch diese API miteinander kommunizieren können.
Stefan2 wrote:Hat einer einen Link zum Ursprung von WM_ messages?
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927.aspx
Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.
...
The system passes input to a window procedure in the form of a message. Messages are generated by both the system and applications.
...
[/OT]
TC plugins: PCREsearch and RegXtract
Pauli
Junior Member
Junior Member
Posts: 24
Joined: 2010-01-13, 08:22 UTC

Post by *Pauli »

Soweit Danke, ich weiß Bescheid und die ersten Macros in AHK laufen ...

Der TC Kauf rückt näher, wenn es so weiter geht und ich meine Workflows von SC nach TC hinbekomme!

Wie Debugged Ihr denn ein AHK Script?

Gruß, Pauli
User avatar
Stefan2
Power Member
Power Member
Posts: 4133
Joined: 2007-09-13, 22:20 UTC
Location: Europa

Post by *Stefan2 »

2milo1012
>>> Das ist einfach die Spezifikation der Schnittstelle..


Aha, ok, danke :thumpsup:

Ich ging da immer von der Programmiersprache aus.
Das es davor noch eine Designabteilung gegeben hatte, habe ich nicht bedacht.




 
User avatar
Stefan2
Power Member
Power Member
Posts: 4133
Joined: 2007-09-13, 22:20 UTC
Location: Europa

AutoHotkey: AHK script debugging

Post by *Stefan2 »

Pauli wrote:
Wie Debugged Ihr denn ein AHK Script?


Show a msgbox:

Code: Select all

MsgBox, 33 , DEBUG, The var value is >%myvar%<`n`nContinue? = [OK] (or Cancel)
IfMsgBox, Cancel
	ExitApp
--OR

Write to a log file:

Code: Select all

FormatTime, vsTimeStamp, , yyyy-MM-dd hh:mm:ss tt    

FileAppend, %vsTimeStamp%: The value of the var is >%myvar%<`n, My Log File.txt 
;OR just use %A_NOW% instead of %vsTimeStamp%.
;FileAppend closes the file every time. That can be a lot of opening/closing a file.
Daher vieleicht besser im Skript die Meldungen sammeln, und am Ende einmal komplett ausgeben:

Code: Select all

loop 3
{
    vDebugOut .= A_NOW ": The value of the var is: "  A_index "`n"
}
FileAppend,  %vDebugOut%, My Log File 2.txt

--


Debugging a Script
Create "break points" in the script:

Code: Select all

ListVars
Pause
When the script encounters these two lines, it will display the current
contents of all variables for your inspection. When you're ready to
resume, un-pause the script via the File or Tray menu.

Code: Select all

loop 5
{
    if(A_Index = 4){
        Msgbox When the script encounters these two lines, it will display the current contents of all variables for your inspection. 
        ListVars
        Msgbox When you're ready to resume, un-pause the script via the File or Tray menu.
        Pause 
    }
    Msgbox % A_Index
}

The following commands are also useful for debugging:
ListLines [, On|Off] ;Displays the script lines most recently executed.
ListVars ;Displays the script's variables: their names and current contents.
KeyHistory ;Displays script info and a history of the most recent keystrokes and mouse clicks.
ListHotkeys ;Displays the hotkeys in use by the current script,
OutputDebug, Text ;Sends a string to the debugger (if any) for display.
Pause [, On|Off|Toggle, OperateOnUnderlyingThread?] ;Pauses the script's current thread.
#p::Pause ; Pressing Win+P once will pause the script. Pressing it again will unpause.
Suspend [, Mode] ;Disables or enables all or selected hotkeys and hotstrings.


OutputDebug, Text :> , zB mit Sysinternals DebugView

zTEST.ahk

Code: Select all

MsgBox Launch Sysinternals DebugView first...
loop 3
{
    msgbox % A_index
    OutputDebug, %A_index% 	;Sends a string to the debugger (if any) for display. 
}
Pauli
Junior Member
Junior Member
Posts: 24
Joined: 2010-01-13, 08:22 UTC

Post by *Pauli »

Super + Danke!
Post Reply